Methods

Spatial data preparation

Load data

Maps data

We use three different shapefiles for the continental U.S. land mass, the State waters of maine, new hampshire, massachusets, connecticut, rhode island, new york, new jersey, delaware, maryland, virginia, north carolina and the North East EEZ. Moreover, we use the NOAA dataset of landings per port.

1.- Land shapefile

Covers the US land territory for visualization. Data provided from the map package.


States <- c("maine", "new hampshire", "massachusetts", "connecticut", "rhode island", "new york", "new jersey", "delaware", "maryland", "virginia", "north carolina") 

# -------------- #
# US State Map (land)
# -------------- #

land_sf <- st_as_sf(map("state", plot = FALSE, fill = TRUE)) %>% 
  filter(ID %in% States) %>% 
  mutate(abrev = c("CT","DE","ME","MD","MA","NH","NJ","NY","NC","RI","VA"),
         state = str_to_sentence(ID)
         )

# Visual exploration (o.k! )
ggplot(land_sf) +
  geom_sf(aes(fill = state)) +
  scale_fill_manual(values = state_pallet) +
  theme_dark()

NA
NA
2.- EEZ shapefile

Used the Sea Around Us shapefle updated to June 2016.


# US EEZ map
path_world <- my_path("G", extra_path = "Spatial/SAU/SAU_Shapefile", name = "SAUEEZ_July2015.shp")

# Load it!
eez_sf <- st_read(path_world) %>%
  rename(eez_name = Name) %>%
  st_transform(crs = 4326) %>% # 4326
  filter(eez_name == "USA (East Coast)") %>%
  st_simplify(preserveTopology = TRUE, dTolerance = 0.1) #0.1 for paper
Reading layer `SAUEEZ_July2015' from data source 
  `/Volumes/Enterprise/Data/Spatial/SAU/SAU_Shapefile/SAUEEZ_July2015.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 280 features and 7 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -180 ymin: -63.66443 xmax: 180 ymax: 87.02394
Geodetic CRS:  WGS 84
Warning in st_simplify.sfc(st_geometry(x), preserveTopology, dTolerance) :
  st_simplify does not correctly simplify longitude/latitude data, dTolerance needs to be in decimal degrees
# Visual exploration (o.k! )
ggplot(eez_sf) +
  geom_sf() +
  theme_dark()

3.- State waters

Covers the state waters of the NE US states. Data from data.gov.

License: No license information was provided. If this work was prepared by an officer or employee of the United States government as part of that person’s official duties it is considered a U.S. Government Work.



state_sf <-  st_read("~/OneDrive - UW-Madison/FederalAndStateWaters/FederalAndStateWaters.gdb") %>%
  janitor::clean_names() %>% 
  mutate(jurisdicti = str_to_lower(jurisdicti)) %>% 
  filter(jurisdicti %in% States) %>% 
  mutate(state = str_to_sentence(jurisdicti)) %>% 
  st_transform(crs = 4326) %>%   # for matching projections
  st_simplify(preserveTopology = TRUE, dTolerance = 10000) #0.1 for paper
Reading layer `FederalAndStateWaters' from data source 
  `/Users/jepa/OneDrive - UW-Madison/FederalAndStateWaters/FederalAndStateWaters.gdb' 
  using driver `OpenFileGDB'
Warning in CPL_read_ogr(dsn, layer, query, as.character(options), quiet,  :
  GDAL Message 1: organizePolygons() received a polygon with more than 100 parts. The processing may be really slow.  You can skip the processing by setting METHOD=SKIP, or only make it analyze counter-clock wise parts by setting METHOD=ONLY_CCW if you can assume that the outline of holes is counter-clock wise defined
Simple feature collection with 40 features and 6 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -20037510 ymin: -1972646 xmax: 20037510 ymax: 12766910
Projected CRS: WGS 84 / World Mercator
Warning in st_simplify.sfc(st_geometry(x), preserveTopology, dTolerance) :
  st_simplify does not correctly simplify longitude/latitude data, dTolerance needs to be in decimal degrees
# Visual exploration (o.k! )
ggplot(state_sf) +
  geom_sf(aes(fill = state)) +
  scale_fill_manual(values = state_pallet) +
  theme_dark()

4.- Fishing ports
4.1 NOAA’s data

Dataset provider: Joe Myers NOAA

Non-confidential dataset containing annual landings/value summaries by port for black sea bass, scup and summer flounder, from NC-ME for 1970-2020.

In order to make the report non-confidential, I am displaying as much of the port-level summary data as I can – and for cases where the port-level was confidential, I have first attempted to roll-up any confidential port-level summaries into state-level summaries within the same year. If those state-level summaries continue to be confidential, I have further rolled-up those confidential ports across states into a coast-level summary. Even at the coast level, there were several cases where not enough confidential ports could be combined to produce a non-confidential summary – and so for those rows it was necessary to redact the final landings/value data. Fortunately, this only amounts to less than 0.5% of the total landings data (characterized in the “Pivot by Confidentiality” tab of the spreadsheet).

License???.

4.1.1 Top ports
# Get number of ports in the NOAA database
overall_port_data <- ports_data %>%
  filter(year >= 2010 & year <= 2019) %>% 
  group_by(species_name,port_name,state_postal) %>% 
  summarise(
    year_ton = sum(total_live_pounds),
    year_value = sum(total_value)
  ) 
`summarise()` has grouped output by 'species_name', 'port_name'. You can override using the `.groups` argument.
4.1.2 Ports coordinates
4.1.1 Visualization

Create base shapefile for computation

As a first step we need to divide the NE US EEZ among the different states. For that, we expanded a buffer-polygon to the 200 nautical miles to then estimate the percentage that each expanded polygon occupied. For the initial buffer point we used two approaches; state waters and US ports. Note that in all cases these areas overlapped and percentages accounted for it. We did this by following these steps:

    1. Expand state waters / US ports using a buffer
    1. Grid that buffer on a 0.3 resolution
    1. Crop the buffer to the EEZ

1. Expand Spatial regions (a.k.a buffers)

1.1 State Waters

We set a buffer of 410000 m (410 km, ~ 221 nm) that overshoots the EEZ a bit, but is eventually cropped


# Buffer state waters
state_bf = st_buffer(state_sf, 4) %>% 
  st_transform(4326) %>% # to match shape
  st_set_crs(4326)

# ------------------------------ #
# Testing and visualizing the buffer 
# ------------------------------ #

state_bf_plot <- ggplot() +
  geom_sf(data = state_sf, aes(color = state), fill = NA) +
  geom_sf(data = eez_sf, aes(), fill = NA) +
  geom_sf(data = state_bf, aes(color = state), fill = NA) +
  scale_color_manual(values = state_pallet)+
  theme_dark()
#   

# ggsave("../Results/Partial/state_waters_buffer.png",state_bf_plot)

# ------------------------------ #

state_bf_plot
1.1 US. Ports

We set a buffer of 5 deg (510 km, ~ 221 nm) that overshoots the EEZ a bit, but is eventually cropped

2. Expand grid within buffer

Here we expand a grid within the buffer so we can estimate the proportion of each state.

Note: Dark grey shaded area is the grid and is the same for both approaches

2.1 Create grid for interpolation

2.1 Merge grid and buffers

Once we have a gridded area, we converted the grid to a sf so we can merge it with the buffered states and ports and finally filter out everything outside the states polygon

2.1.1 State Waters

# ---------------- #
# Convert grid to sf
# ---------------- #
grid_sw_sf <- st_as_sf(ne_grid,
             coords = c("lon", "lat"),
             crs = 4326) %>% 
  st_join(state_bf) %>% 
  filter(!is.na(state))

# Create data frame for future computations
# Note, will be used in next chunk
grid_sw_bf_dt <- as.data.frame(grid_sw_sf) %>%
    select(index,state)
    # group_by(state) %>% 
    # summarise(length(index))


# ---------------- #
# [TEST] 
# Visualization of grid
# ---------------- #

gridExtra::grid.arrange(
  # Overall (overlapping) position
  ggplot(grid_sw_sf) +
    geom_sf(data = state_sf, aes(), fill = NA) +
    geom_sf(aes(color = state), alpha = 0.3) +
    geom_sf(data = eez_sf, aes(),fill =NA) + 
    scale_color_manual(values = state_pallet) +
    theme_dark() +
    theme(legend.position = ""),
  # Showing each state separatley
  ggplot() +
    geom_sf(data = grid_sw_sf, aes(color = state),size = 0.1, alpha = 0.5) +
    facet_wrap(~state) +
    theme_dark() +
    theme(legend.position = "top") +
    scale_color_manual(values = state_pallet),
  nrow = 1) 
2.1.1 Fishing Ports

3. Crop buffers to EEZ

Finally, we crop the grided buffers to within the EEZ to capture the actual water space.

Note: This step takes quite a while because of the size of the EEZ shapefile. No, you cannot use st_simplify() here

3.1 State Waters

grid_eez_sw_sf <- st_intersection(grid_sw_sf,eez_sf)
Error in st_intersection(grid_sw_sf, eez_sf) : 
  object 'grid_sw_sf' not found

3.2 Fishing Ports

3.3 Differences at croped level

By looking at the plots we do not see that the number of grid cells that each state has is slightly different depending on the approach. This comes to light when we count the number of gridcells that each state gets in each approach. We see that the state waters one is substantially higher.

We can visualize the difference of the cropped area for each state next. Again, the fishing port approach results in less area for all states, but such area is not proportional among states. For example, Delaware looses roughly 35% of fishing grounds with this approach


grid_eez_sw_df %>% 
  mutate(approach = "state_waters") %>% 
  bind_rows(grid_eez_fp_df) %>%
  mutate(approach = ifelse(is.na(approach),"fishing_port",approach)) %>% 
  group_by(state,approach) %>% 
  summarise(n_grid = n()) %>% 
  spread(approach,n_grid) %>% 
  mutate(difference =state_waters-fishing_port,
         percentage_sw = round((difference/state_waters)*100)
         )

And here is the map visualization of the cropped difference


grid_eez_sw_df %>% 
  mutate(approach = "state_waters") %>% 
  bind_rows(grid_eez_fp_df) %>%
  mutate(approach = ifelse(is.na(approach),"fishing_port",approach)) %>% 
  ggplot() +
  geom_tile(
    aes(
      x = lon,
      y = lat,
      fill = approach
    ),
    alpha = 0.5
  ) +
  facet_wrap(~state) +
  scale_color_brewer(palette = "Set2") +
  scale_fill_brewer(palette = "Set2") +
  theme_dark()

Interpolation rutine

In this step we interpolate the survey data within the previously created grid following a Triangular Irregular Surface method.

Functions needed

We need to create a couple of functions to run the whole process

Interpolation main fx (tis).

This is the main function used to interpolate the data per year. It follows a Triangular Irregular Surface method using the interp::interp() function. If you want to see the function clic on code


tis <- function(input_data, grid, yr, taxa, reg){
  
  # --------------- #
  # Testing
  # print(paste(yr))
  # yr = 1976
  # --------------- #
  
  # Filter data
  data <- input_data %>% 
    filter(year == yr,
           spp == taxa,
           region == reg
    ) %>% 
    # Average duplicated hauls in the same spot
    group_by(region,year,spp,lat,lon) %>%
    summarise_at(vars(wtcpue),
                 mean,na.rm = T)
    
  # Only interpolate cases where there is more than 3 rows
  # Marked by the function 
    if(nrow(data) <= 3){
      fit_tin <- tibble()
    }else{
      
      # Triangular Irregular Surface
      fit_tin <- interp::interp( # using {interp}
        x = data$lon,           # the function actually accepts coordinate vectors
        y = data$lat,
        z = data$wtcpue,
        xo = grid$lon,     # here we already define the target grid
        yo = grid$lat,
        output = "points"
      ) %>% 
        bind_cols() %>% 
        bind_cols(grid) %>%
        mutate(year = yr,
               region = reg,
               spp = taxa) %>% 
        select(index, 
               # state,
               year, region, spp, lon=x, lat=y, value = z)
      
    }
   
    return(fit_tin)
}

# Test me
# Needs variables in Control panel
# Test no data: "Alosa aestivalis", reg = "Northeast US Fall", yr = 1974 
# tis(input_data = ocean_data, grid = grid_eez_df, taxa = "Illex illecebrosus", reg = "Northeast US Fall", yr = 1973)



# lapply(years,tis,input_data = ocean_data, grid = grid_eez_df, taxa = "Illex illecebrosus", reg = regions[2])
Run function

This is a sub-function that runs the tis() function by taxa and region. It saves the output as a .csv file for each species.



run_tis <- function(input_data, grid, years, taxa, reg){
  
  
  # Run tis for species and surveys
  for(r in 1:2){
    
    partial_df <- bind_rows(
      lapply(years,tis,input_data = input_data, grid = grid, taxa = taxa, reg = reg[r])
    )
    
    if(r == 1){
      historic_tif <- partial_df
    }else{
      historic_tif <- bind_rows(historic_tif,partial_df)
    }
    
  }
  
  # ----------------------- #
  # Save dataset per species
  # ----------------------- #
  
  # Set file name
  name <- paste0("tif_",str_replace(taxa," ","_"),".csv")
  
  complement <- paste0("Partial/Interpolation/")
  
  # Set path name
  save_path <- my_path("R",complement)
  
  # Set complete path
  save_name <- paste0(save_path,name)
  
  # Create folder if it does not exist
  if(file.exists(save_path) == F){
    dir.create(save_path)
  }
  
  #  Save file
  write_csv(historic_tif,save_name)
  
  return_msg <- paste("Interpolation done for", taxa)
  
  return(return_msg)
  
  
}

# Test me
    # run_tis(input_data = ocean_data, grid = grid_eez_fp_df, taxa = "Centropristis striata", years = seq(1970,1980), reg = regions, method = "testa")

Survey data

The interpolation was done with NOAA Northeast Fisheries Science Center Spring and Fall Bottom Trawl Surveys data provided by Ocean adapt. Data was accessed trough the Github.

In primary publications using data from the database, please cite Pinsky et al. 2013. Marine taxa track local climate velocities. Science 341: 1239-1242 doi: 10.1126/science.1239352, as well as the original data sources.

  • Using only the Northeast US Fall and Spring bottom trawl survey data for now
Splitting up data
  • No part on spatial analysis. Can be ignored.

This is just a sub-step to split up the data into single species files. This makes the app faster as it only needs to load species specific data, rather than all the data at de beginning.

Control Pannel

This is where we load the required data and prepare to run the interpolation function. Note that some of the data here has been previously created


# Load grid df
# For fishing ports
inter_grid <- my_path("D","Spatial","inter_grid_df.csv", read = T)

# Run interpolation for all years
years <- seq(1973,2019,1)

# regions
regions <- c("Northeast US Fall" , "Northeast US Spring")

# species list
spp <- ocean_data %>% 
  filter(region %in% regions,
         spp != "NA") %>% 
  pull(spp) %>% 
  unique()


# Double check runs

spp_runs <- tibble(taxa = (list.files(my_path("R","Partial/Interpolation/fp")))) %>%
  mutate(
    taxa = str_remove(taxa, "tif_"),
    taxa = str_remove(taxa, ".csv"),
    taxa = str_replace(taxa, "_", " ")
  ) 

# Missing runs
spp <- tibble(taxa=spp) %>% 
  anti_join(spp_runs) %>% 
  pull(taxa)

Run routine

Here we just run the routine for each of the species present in the Northeast US Fall and Spring surveys between 1973 and 2019.

  • Note there are 43 identified taxa
  • Some taxa do not have presence data in some years

# # single species run
run_tis(input_data = ocean_data,
        grid = grid_eez_fp_df,
        years = years,
        reg = regions,
        taxa = "Stenotomus chrysops",
        method = "fp"
)


# Run them all in parallel
lapply(Species,
       run_tis, 
       input_data = ocean_data,
       grid = inter_grid,
       years = years,
       reg = regions
)

Results

Results are now for eight species managed under Mid-Atlantic Council Management Plans according to NOAA.

State allocations of the commercial black sea bass coastwide quota were originally implemented in 2003 as part of Amendment 13, loosely based on historical landings from 1980- 2001.

Scomber scombrus, Peprilus triacanthus (butterfish), Illex illecebrosus (shortfin squid), Paralichthys dentatus (summer flounder), Stenotomus chrysops (Scoop), Centropristis striata (black sea bass), Pomatomus saltatrix (Bluefish), Lopholatilus chamaeleonticeps (Golden tilefish), Caulolatilus microps (blueline tilefish) and Clupea harengus


# Spatial data
States <- c("maine", "new hampshire", "massachusetts", "connecticut", "rhode island", "new york", "new jersey", "delaware", "maryland", "virginia", "north carolina") 

# US State Map (land)
land_sf <- st_as_sf(map("state", plot = FALSE, fill = TRUE)) %>% 
  filter(ID %in% States) %>% 
  mutate(abrev = c("CT","DE","ME","MD","MA","NH","NJ","NY","NC","RI","VA"),
         state = str_to_sentence(ID)
         )

# US EEZ map
path_world <- my_path("G", extra_path = "Spatial/SAU/SAU_Shapefile", name = "SAUEEZ_July2015.shp")


### Previouslly created grids 

grids <- my_path("D", "Spatial/grid_eez_fp", name = "grid_eez_fp_df.csv", read = T) %>%
  mutate(
    spatial = "fp"
  ) %>% 
  bind_rows(
    my_path("D", "Spatial/grid_eez_sw", name = "grid_eez_sw_df.csv", read = T)
  ) %>% 
  select(-spp) %>% 
  mutate(
    spatial = ifelse(is.na(spatial),"sw",spatial)
  ) %>% 
  distinct(.keep_all = T)
  

# Species data

# Managed species by Mid-Atlantic Council Management Plans, and State waters
# https://www.fisheries.noaa.gov/new-england-mid-atlantic/commercial-fishing/new-england-mid-atlantic-fishery-management-plans

Species <- c(
  "Paralichthys dentatus", #summer flounder
  "Stenotomus chrysops", #Scup"
  "Centropristis striata"#, # black sea bass
  )

spp_paths <- list.files(my_path("R",extra_path = "Partial/Interpolation/"))

# Some gibiris for names
taxon_list <- gsub("_"," ",spp_paths)
taxon_list <- gsub("tif ","",taxon_list)
taxon_list <- gsub(".csv","",taxon_list)

taxon_list <- taxon_list[taxon_list %in% Species]

# Now set a list of files to read
taxon_read <- paste0("tif_",taxon_list,".csv")
taxon_read <- gsub(" ","_",taxon_read)

taxon_read <- spp_paths[spp_paths %in% taxon_read]

#### Load sw interpolation 

taxon_sw <- my_path("R",extra_path = "Partial/Interpolation/", name = taxon_read)

# Load all sp in one table
historic_spp <- bind_rows(lapply(taxon_sw, fread)) %>% 
  left_join(grids,
            by = c("index","lon","lat")
  ) %>%
  filter(!is.na(spatial)) %>% 
  mutate(
    season = ifelse(str_detect(region,"Spring"),"Spring","Fall"),
    label = ifelse(spp == "Paralichthys dentatus" & year >= 1980 & year <= 1986,"Reference",
                   ifelse(spp == "Stenotomus chrysops" & year >= 1988 & year <= 1992,"Reference",
                          ifelse( spp =="Centropristis striata" & year >= 1980 & year <= 2001,"Reference",
                                 ifelse(year > 2001,"Today",NA)
                          )
                   )
    )
  )

# historic_spp %>% 
#   filter(is.na(spatial)) %>% 
#   filter(year == 1973,
#          region == "Northeast US Fall") %>% 
#   ggplot() +
#     geom_tile(
#       aes(
#         x = lon,
#         y = lat,
#         fill = index
#       )
#     ) +
#   facet_grid(spp~state) + 
#   geom_sf(data = land_sf,aes()) +
#   geom_sf(data = eez_sf, aes(), fill =NA)

unique(historic_spp$spp)
unique(historic_spp$region)
unique(historic_spp$season)

# Periods
periods <-tibble(
  order = c(rep("a",12),
            rep("b",12),
            rep("c",12),
            rep("d",11)
  ),
  label = c(rep("1973-1984",12),
            rep("1985-1996",12),
            rep("1997-2008",12),
            rep("2009-2019",11)
  ),
  year = c(seq(1973,1984,1),
           seq(1985,1996,1),
           seq(1997,2008,1),
           seq(2009,2019,1)
  )
  )


state_lat <- historic_spp %>%
  group_by(state) %>% 
  summarise(
    order = mean(lat)
  ) %>% 
  filter(!is.na(state)) %>% 
  mutate(abrev = c("CT","DE","ME","MD","MA","NH","NJ","NY","NC","RI","VA")
  ) %>% 
  arrange(desc(order)) %>% 
  mutate(lat = order,
    # order = letters[1:11],
    order = c("b","a",letters[3:11]),)



# State pallet

state_pallet <- c(wes_palette(n = 5, name = "Darjeeling1"),
                               wes_palette(n = 5, name = "Darjeeling2"),
                               # wes_palette(n = 2, name = "GrandBudapest1")
                  "#FD6467"
                  )



# print for notebook
head(historic_spp)

Regulatory units result

#### Data needed ####

# Get state order from North to south
state_order <- my_path("D","Spatial/grid_eez_sw", name = "grid_eez_sw_df.csv",read = T) %>%
  group_by(state) %>% 
  summarise(
    order = mean(lat)
  ) %>% 
  mutate(abrev = c("CT","DE","ME","MD","MA","NH","NJ","NY","NC","RI","VA")
  ) %>% 
  arrange(desc(order)) %>% 
  mutate(order= c("b","a",letters[3:11])) %>% # weirdly maine goes below
  arrange(order)



# Load grid of state waters
grid_eez_sw_sf <-  st_read(my_path("D","Spatial/grid_eez_sw", name = "grid_eez_sw_sf.shp")) %>%
  select(index,state,geometry) %>% 
  mutate(method = "state_waters",
         state = str_to_sentence(state)) %>% 
  left_join(state_order)

grid_eez_sw_sf$group <- factor(grid_eez_sw_sf$abrev,      # Reordering group factor levels
                               levels = state_order$abrev)


# Load grid of fishing ports
grid_eez_fp_sf <-  st_read(my_path("D","Spatial/grid_eez_fp", name = "grid_eez_fp.shp")) %>%
  select(index,abrev=lndng_s,geometry) %>% 
  mutate(method = "fishing_port"#,
         # state = str_to_sentence(landing_port)
         )%>% 
  left_join(state_order)


grid_eez_fp_sf$group <- factor(grid_eez_fp_sf$abrev,      # Reordering group factor levels
                               levels = state_order$abrev)

grid_eez_fp_sf <- arrange(grid_eez_fp_sf,group)
# Plotting 
# Make sure st_simplify() is run for eez sf

# State waters plot

p_sw <- gridExtra::grid.arrange(
  # Overall (overlapping) position
  ggplot(grid_eez_sw_sf) +
    geom_sf(data = eez_sf, aes(), fill = "white") + 
    geom_sf(aes(color =group , fill = group), alpha = 0.3) +
    geom_sf(data = land_sf, aes()) +
    ggsflabel::geom_sf_label_repel(data = land_sf, aes(label= abrev), 
                                   size = 4,
                                   box.padding = 0.10,
                                   hjust = 1) +
    scale_color_manual(values = state_pallet) +
    scale_fill_manual(values = state_pallet) +
    my_ggtheme_p(leg_pos = "",
                 ax_tx_s = 13) +
    coord_sf(ylim = c(30,48)) +
    scale_y_continuous(breaks = c(30,35,40,45))+
    labs(x = "", y = "", title = "A) State waters approach") +
    theme(plot.title = element_text(size = 20)),
  # Showing each state separately
  ggplot(grid_eez_sw_sf) +
    geom_sf(data = land_sf, aes(), fill = "grey80") +
    geom_sf(aes(color = group),size = 0.1, alpha = 0.3) +
    facet_wrap(~ group) +
    theme(legend.position = "top") +
    scale_color_manual(values = state_pallet,
                       # labels = unique(grid_eez_sw_sf$group)) +
                       labels = grid_eez_sw_sf %>% arrange(order) %>%  pull(state) %>% unique()) +
    ggtitle("") +
    my_ggtheme_p(leg_pos = "",
                 ax_tx_s = 11,
                 axx_tx_ang = 45,
                 hjust = 1
    ),
  nrow = 1)


##### ------------- ####
# Fishing Ports plot
##### ------------- ####


grid_eez_fp_sf <-
  grid_eez_sw_sf %>% 
  filter(!group %in% grid_eez_fp_sf$group) %>% 
  mutate(index = NA) %>% 
  bind_rows(grid_eez_fp_sf)
  
  


p_fp <- gridExtra::grid.arrange(
  # Overall (overlapping) position
  ggplot(data = subset(grid_eez_fp_sf, index != "NA")) +
    geom_sf(data = eez_sf, aes(), fill = "white") + 
    geom_sf(aes(color = group, fill = abrev), alpha = 0.3) +
    geom_sf(data = land_sf, aes()) +
    ggsflabel::geom_sf_label_repel(data = land_sf, aes(label= abrev), 
                                   size = 4,
                                   box.padding = 0.10,
                                   hjust = 1) +
    # scale_color_manual(values = state_pallet) +
    # scale_fill_manual(values = state_pallet) +
    scale_color_manual(values = c(state_pallet[3:4],state_pallet[6:13])) +
    scale_fill_manual(values = c(state_pallet[3:4],state_pallet[6:13])) +
    my_ggtheme_p(leg_pos = "",
                 ax_tx_s = 13) +
    coord_sf(ylim = c(30,48)) +
    scale_y_continuous(breaks = c(30,35,40,45)) +
    labs(x = "", y = "", title = "B) Fishing ports approach") +
    theme(plot.title = element_text(size = 20)),
  # Showing each state separately
  ggplot() +
    geom_sf(data = subset(grid_eez_fp_sf, index = "NA"), color = "white") +
    geom_sf(data = subset(grid_eez_fp_sf, index != "NA"), aes(color = group),size = 0.1, alpha = 0.3) +
    geom_sf(data = land_sf, aes(), fill = "grey80") +
    facet_wrap(~ group) +
    geom_point(data = rename(ports_df, group = landing_state), aes(x = lon, y = lat), color = "#E6A0C4") +
    theme(legend.position = "top") +
    # scale_color_manual(values = state_pallet,
    scale_color_manual(values = c(state_pallet[3:4],state_pallet[6:13]),
                       # labels = unique(grid_eez_fp_sf$group)) +
                       labels = grid_eez_fp_sf %>% arrange(order) %>%  pull(state) %>% unique()) +
    ggtitle("") +
    my_ggtheme_p(leg_pos = "",
                 ax_tx_s = 11,
                 axx_tx_ang = 45,
                 hjust = 1
    ),
  nrow = 1)



combined_plot <- gridExtra::grid.arrange(p_sw,p_fp,
                                         bottom = "Longitude",
                                         left = "Latitude")

ggsave(filename = "buffer_figure.jpg",
       plot = combined_plot,
       path = my_path("R","Figures"),
       width = 11,
       height = 11
       )

Interpolation result


# Interpolation data
interpol_result <- historic_spp %>% 
  filter(!is.na(label)) %>% 
  group_by(label,index,spp,season,lat,lon) %>% 
  summarise(mean_cpue = mean(value,na.rm=T)) %>% 
  filter(!is.na(mean_cpue))


# Paper numbers

# interpol_result %>% 
#   filter(mean_cpue >0) %>% 
#   View()

# --------------------- #
# Biomass Centroid shift
# --------------------- #

# Estimate total interpolation
total_inter <- historic_spp %>% 
  filter(!is.na(label)) %>% 
  group_by(spp,index,season) %>% 
  summarise(mean_cpue = mean(value,na.rm=T)) %>% 
  group_by(spp,season) %>% 
  summarise(total_cpue = sum(mean_cpue, na.rm = T))


# Estimate centroid based on top 10 grids with higer abundance
centroid_db <- historic_spp %>% 
  filter(!is.na(label)) %>% 
  group_by(label,index,spp,season,lat,lon) %>% 
  summarise(mean_cpue = mean(value,na.rm=T)) %>% 
  filter(!is.na(mean_cpue)) %>% 
  left_join(total_inter) %>% 
  mutate(
    per_cpue = round((mean_cpue/total_cpue)*100,2)
  ) %>% 
  group_by(spp,label,season) %>% 
  top_n(10,per_cpue) %>% 
  group_by(spp,label,season) %>% 
  summarise(
    lat = mean(lat),
    lon = mean(lon)
  )

# Paper numbers
# centroid_db %>% 
#   select(-lon) %>% 
#   spread(label,lat) %>% 
#   mutate(diff = Today-Reference) %>% 
#   View()


# For alternative color pallet
pal <- wes_palette("Zissou1",100,type = "continuous")

inter_map <- ggplot() +
  geom_tile(data = subset(interpol_result, mean_cpue == 0),
            aes(
              x = lon,
              y = lat
            ),
            fill = "grey90",
            color = "grey90"
  ) + 
  geom_tile(data = subset(interpol_result, mean_cpue > 0),
            aes(
              x = lon,
              y = lat,
              fill = log10(mean_cpue),
              color = log10(mean_cpue)
              # fill = mean_cpue,
              # color = mean_cpue
            )
  ) + 
  geom_point(data = centroid_db,
             aes(
               x = lon,
               y = lat
             ),
             shape = 3,
             color = "white"
  ) + 
  geom_sf(data = land_sf,aes()) +
  labs(x = "Longitude",
       y = "Latitude") +
  # ggsflabel::geom_sf_label_repel(data = land_sf, aes(label= abrev), 
  #                                  size = 4,
  #                                  box.padding = 0.10,
  #                                  hjust = 1) +
  # Viridis option
# scale_fill_viridis("CPUE",
#                    limits = c(0,40),
#                    # limits = c(-5,1), # for log10
#                    direction = -1,
#                     end = 0.9
#                    ) +
# scale_color_viridis("CPUE",
#                     limits = c(0,40),
#                     # limits = c(-5,1), # for log10
#                     direction = -1,
#                     end = 0.9
#                     ) +
# wes anderson option
scale_fill_gradientn("CPUE",
                     colours = pal,
                     # limits = c(0,40) # For cpue
                     limits = c(-5,1) # for log10

) +
  scale_color_gradientn("CPUE",
                        colours = pal,
                        # limits = c(0,40) # for cpue
                        limits = c(-5,1) # for log10
  ) +
  facet_grid(spp~season+label) +
  my_ggtheme_m(map_type = "na", leg_pos = "right",ax_tx_s = 7,ax_tl_s = 10,leg_tx_s = 12) #+
# theme(legend.key.width = unit(3,"line"))


ggsave("interpolation_wa.jpg",
       inter_map,
       path = my_path("R","Figures"),
       width = 9,
       height = 7)

Average proportion

This map shows the aggregated extrapolated value from all three species per State average across the whole study period within each State’s water.

Note: This is intended to be a supplemental figure


data_grid <- historic_spp %>% 
  group_by(state,lat,lon,region,spatial) %>% 
  summarise(sum = sum(value,na.rm= T), .groups = "drop") %>% # sum of all species
  group_by(state,lat,lon,region,spatial) %>% 
  summarise(mean = mean(sum,na.rm= T), .groups = "drop") # average of all years


ggplot(data = subset(data_grid, !is.na(mean))) +
  geom_tile(
    aes(
      x = lon,
      y = lat,
      fill = mean,
      col = mean
    )
  ) +
  geom_sf(data = land_sf, aes()) +
  facet_wrap(~ state  +  region + spatial) +
  labs(x = "Longitude", y = "Latitude") +
  scale_fill_viridis("Mean Interpolation", alpha = 0.8) +
  scale_color_viridis("Mean Interpolation", alpha = 0.8) +
  theme_bw()

Proportion Change

Here we show the average proportion of the interpolation by State and time period. Time periods were arbitrary defined as;

  • Early; 1973 to 1984
  • Mid; 1985 to 1997
  • Late; 1998 to 2011
  • Now; 2012 to 2019

Notes: Figure represents the Spring survey. This computation considers the Overlapping of state waters.

Data preparation

total_fited <- historic_spp %>% 
  group_by(year,season,spp,spatial) %>% 
  summarise(total_value = sum(value,na.rm=T),.groups = "drop")


state_fit <- historic_spp %>% 
  group_by(state,year,label,season,spp,spatial) %>% 
  summarise(state_value = sum(value,na.rm= T), .groups = "drop") %>% 
  # View()
  left_join(total_fited,
            by = c("year","season","spp","spatial")) %>%
  mutate(percentage = state_value/total_value*100) %>% 
  group_by(state,label,season,spp,spatial) %>% 
  summarise(mean_per = round(mean(percentage)),.groups = "drop") %>% 
  #Only show results for spring
  filter(!is.na(label))

Regulatory units map

reg_unit <- state_fit %>% 
  filter(season == "Spring") %>% 
  spread(spatial,mean_per) %>% 
  # Set NA's to 0 because no data found on FP
  mutate(fp = replace_na(fp,0)) %>% 
  # View()
  mutate(
    difference = abs(fp-sw),
    difference = ifelse(difference > 100,100,
                        ifelse(difference < -100,-100,difference)
    )
  ) %>% 
  gather("spatial","mean_per",fp:difference) %>% 
  mutate(spp = gsub(" ","\n",spp),
         spatial = ifelse(spatial == "fp","Fishing ports",
                          ifelse(spatial == "sw","State waters","Difference")
         )
  )


# The plot
map_plot <- land_sf %>% 
  left_join(reg_unit,
            by = "state") %>% 
  filter(spatial != "Difference") %>% 
  ggplot() +
  geom_sf(aes(fill = mean_per)) +
  viridis::scale_fill_viridis("Average proportion per State", alpha = 0.8, 
                              breaks = seq(0,35,5),
                              limits=(c(0,35))
                              )+
  facet_grid(spatial~ spp+label) +
  labs(x = "", 
       y = "") +
  my_ggtheme_p(facet_tx_s = 20,
               leg_pos = "bottom",
               axx_tx_ang = 45,
               ax_tx_s = 12,
               ax_tl_s = 18,
               hjust = 1) +
  theme(legend.key.width = unit(4,"line")) 


diff_plot <- land_sf %>% 
  left_join(reg_unit,
            by = "state") %>% 
  filter(spatial == "Difference") %>% 
  ggplot() +
  geom_sf(aes(fill = mean_per)) +
  viridis::scale_fill_viridis("Difference (%)", alpha = 0.8,option = "C",
                              breaks = seq(0,20,5),
                              limits=(c(0,22)),
                              # labels = c("<-10",seq(-75,75,25),">100")
                              ) +
  facet_grid(spatial~ spp+label) +
  labs(x = "", 
       y = "") +
  my_ggtheme_p(facet_tx_s = 20,
               leg_pos = "bottom",
               axx_tx_ang = 45,
               ax_tx_s = 12,
               ax_tl_s = 18,
               hjust = 1) +
  theme(legend.key.width = unit(4,"line"),
        strip.background = element_blank(),
        strip.text.x = element_blank()
        ) 


# Cowplot option
p <- ggdraw() +
  # Revenue circular
  draw_plot(map_plot, x = 0, y = 0.2, width = 1, height = 0.8) +
  # Catch circular
  draw_plot(diff_plot, x = 0, y = 0, width = 1, height = 0.4) +
  draw_plot_label(label = c("Latitude", "Longitude"), 
                  size = 18,
                  angle = c(90,0),
                  x = c(0,0.45), 
                  y = c(0.45,0.15)
  )
  

save_plot(
  path = my_path("R","Figures"),
  "proportion_chg_reg.jpg",
  p,
  base_height = 14,
  base_width = 14
)

reg_unit %>% 
  # filter(spatial == "fp") %>%
  select(-fp) %>% 
  spread(label,sw) %>% 
  mutate(
    difference = Today-Reference
    ) %>% 
  gther(Reference:difference)

Seasonal units map

# Get seasonal data
season_fit <- state_fit %>% 
  filter(spatial != "fp") %>%
  spread(season,mean_per) %>%
  mutate(
    Difference = abs(Fall-Spring),
    Difference = ifelse(Difference > 100,100,
                        ifelse(Difference < -100,-100,Difference)
    )
  ) %>% 
  gather("season","mean_per",Fall:Difference) %>% 
  mutate(spp = gsub(" ","\n",spp))

# The plot
map_plot <- land_sf %>% 
  left_join(season_fit,
            by = "state") %>% 
  filter(season != "Difference") %>% 
  ggplot() +
  geom_sf(aes(fill = mean_per)) +
  viridis::scale_fill_viridis("Average proportion per State", alpha = 0.8, 
                              breaks = seq(0,15,5),
                              limits=(c(0,15))
                              )+
  facet_grid(season~ spp+label) +
  labs(x = "", 
       y = "") +
  my_ggtheme_p(facet_tx_s = 20,
               leg_pos = "bottom",
               axx_tx_ang = 45,
               ax_tx_s = 12,
               ax_tl_s = 18,
               hjust = 1) +
  theme(legend.key.width = unit(4,"line")) 


diff_plot <- land_sf %>% 
  left_join(season_fit,
            by = "state") %>% 
  filter(season == "Difference") %>% 
  ggplot() +
  geom_sf(aes(fill = mean_per)) +
  viridis::scale_fill_viridis("Difference (%)", alpha = 0.8,option = "C",
                              breaks = seq(0,5,1),
                              limits=(c(0,5)),
                              # labels = c("<-10",seq(-75,75,25),">100")
                              ) +
  facet_grid(season~ spp+label) +
  labs(x = "", 
       y = "") +
  my_ggtheme_p(facet_tx_s = 20,
               leg_pos = "bottom",
               axx_tx_ang = 45,
               ax_tx_s = 12,
               ax_tl_s = 18,
               hjust = 1) +
  theme(legend.key.width = unit(4,"line"),
        strip.background = element_blank(),
        strip.text.x = element_blank()
        ) 


# Cowplot option
p <- ggdraw() +
  # Revenue circular
  draw_plot(map_plot, x = 0, y = 0.2, width = 1, height = 0.8) +
  # Catch circular
  draw_plot(diff_plot, x = 0, y = 0, width = 1, height = 0.4) +
  draw_plot_label(label = c("Latitude", "Longitude"), 
                  size = 18,
                  angle = c(90,0),
                  x = c(0,0.45), 
                  y = c(0.45,0.15)
  )
  

save_plot(
  path = my_path("R","Figures"),
  "proportion_chg_seas_.jpg",
  p,
  base_height = 14,
  base_width = 14
)

Area plot

This graph shows the proportion of the interpolation value each State has over time.

Note: This plot is interactive. For ease comparison between States you can;

  • One click on any State to remove it from the plot
  • Two clicks on any State to isolate it from the plot (other states can then be added by just clicking on them).
  • The bottom panel allows you to reduce the time frame

Dynamic aggregated plot


total_fited <- historic_spp %>% 
  group_by(year,region) %>% 
  summarise(total_value = sum(value,na.rm=T),.groups = "drop")

# group by state
state_fit <- historic_spp %>% 
  group_by(state,year,region) %>% 
  summarise(state_value = sum(value,na.rm= T), .groups = "drop") %>% 
  left_join(total_fited,
            by = c("year","region")) %>%
  mutate(percentage = state_value/total_value*100)

# Plot me
p <- ggplot(state_fit) +
  geom_area(
    aes(
      x = year,
      y = round(percentage),
      fill = state
    )
  ) +
  ylab("Percentage (%)") +
  # viridis::scale_fill_viridis(discrete = T, alpha = 0.8) +
  scale_fill_manual(values = state_pallet) +
  MyFunctions::my_ggtheme_p() +
  facet_wrap(~region, ncol = 1) +
  theme_dark()

ggplotly(p,
         dynamicTicks = TRUE) %>% 
  layout(hovermode = "x") %>%
  rangeslider()

Area plot (running mean)

This graph shows the proportion of each State smoothed over a *10 years running mean**. It allows to better see increasing and decreasing trends.

Dynamic aggregated plot

Note: This plot is also interactive and thus, follows the same options of the previous one.


# group by state
state_fit <- historic_spp %>% 
  group_by(state,year,region,.groups = "drop") %>% 
  summarise(state_value = sum(value,na.rm= T), .groups = "drop") %>% 
  left_join(total_fited,
            by = c("year","region")) %>%
  mutate(percentage = state_value/total_value*100) %>% 
  group_by(state,region) %>% 
  mutate(RMean = zoo::rollmean(x = percentage, 
                            10,
                            fill = NA,
                            na.rm=T)
    ) %>%  
  left_join(state_lat)

# Plot me
p <- ggplot(state_fit) +
  geom_area(
    aes(
      x = year,
      y = round(RMean),
      fill = state
      # fill = order
    )
  ) +
  ylab("10 yrs running average (%)") +
  scale_fill_manual(
    "State",
    values = state_pallet,
    # labels = state_fit %>% arrange(order) %>%  pull(state) %>% unique()
  ) +
  MyFunctions::my_ggtheme_p() +
  facet_wrap(~region, ncol = 1) +
  theme_dark()

suppressWarnings(
ggplotly(p,
         dynamicTicks = TRUE) %>% 
  layout(hovermode = "x") %>% 
  # add_trace() %>% 
  rangeslider()
)

Aggregated Proportional change

Paper figure: Per Species Proportional change

Old code

Fishing ports WPI

We used Global Fishing Watch’s database on Anchorages, Ports and Voyages.

The Global Fishing Watch anchorages dataset is a global database of anchorage locations where vessels congregate. The dataset contains over 160,000 individual anchorage locations, which are further grouped into nearly 32,000 ports when applicable.


# Get Global Fishig Watch data
gfw_data <- my_path("D","Spatial",name = "gfw_portdata.csv", read = T) %>% 
  filter(iso3 == "USA") 

# Visualize data (o.k!)
# ggplot(gfw_data) +
#   geom_point(
#     aes(
#     x = lon,
#     y = lat
#   )
#   )

# Convert data to sf for mergig
gfw_sf <- st_as_sf(gfw_data,
             coords = c("lon", "lat"),
             crs = 4326)

# Merge data with state waters to,locate ports 
port_sf <- st_join(gfw_sf,state_sf) %>% 
  filter(!is.na(jurisdicti)) # remove points outside stat waters

ggplot(port_sf)  +
  geom_sf(aes(color = distance_from_shore_m)) +
  theme_dark()

So…Looks like some ports are “far from shore” which I don’t really know what it means. For now, I am only selecting those ports that ar 0 meter from shore.

There are still too many ports in each state (?). Specially New Jersey! One approach is to use NOAA’s landing-per-port data to filter out…

4.2 World Port Index

In this approach we only use the ports categorized within the WPI and with distance_from_shore_m == 0 and at_dock == TRUE.

  • at_dock == Anchorages within a 450 meter buffer around a combined land shape file are considered at dock.

Historic quota Vs distributions

This section of the results explores the differences between the historic distribution of te stock and the historic quota allocation. We collected the proportion of the total quota that each State gets for each species.

Right now the analysis only covers black sea bass, summer flounder and scup. But we can go speceis by species to see which ones have their quota allocated by state to include them in the analysis.

Note: We are using the new allocations based on the stock’s most recent biomass distribution*

For State-level managed species see the Atlantic States Marine Fisheries Comission website and go species-by-species.


quota_allocation <- state_lat %>% 
  mutate(
    "Centropristis striata" = c(
      0.0040, #ME
      0.0040, #NH
      0.1564, #MA
      0.1323, #RI
      0.0367, #CT
      0.0857, #NY
      0.2010, #NJ
      0.0411, #DE
      0.0888, #MD
      0.1614, #VA
      0.0888 #NC
    ),
    "Paralichthys dentatus" = c(
      0.0004756, #ME 
      0.0000046, #NH 
      0.0682046, #MA 
      0.1568298, #RI 
      0.0225708, #CT 
      0.0764699, #NY 
      0.1672499, #NJ 
      0.0001779, #DE 
      0.0203910, #MD
      0.2131676, #VA
      0.2744584 #NC
    ),
    "Stenotomus chrysops" = c(
      0.0012101, #ME
      0.0000000, #HN
      0.2158729, #MA
      0.5619456, #RI
      0.0315399, #CT
      0.1582466, #NY
      0.0291667, #NJ
      0.0000000, #DE
      0.0001190, #MD
      0.0016502, #VA
      0.0002490 #NC
    )
  ) %>% 
  gather("spp","quota",4:6)

# Double check they all add to 1...
quota_allocation %>% 
  group_by(spp) %>% 
  summarise_at(vars(quota),sum)


quota_allocation %>% 
  arrange(order) %>% 
  select(-order) %>% 
  spread(spp,quota) %>% 
  kable()

Get data ready


total_fited <- historic_spp %>% 
  group_by(year,region,spp) %>% 
  summarise(total_value = sum(value,na.rm=T),.groups = "drop")

# group by state
state_fit <- historic_spp %>% 
  group_by(state,year,region,spp) %>% 
  summarise(state_value = sum(value,na.rm= T), .groups = "drop") %>% 
  left_join(total_fited,
            by = c("year","region","spp")) %>%
  mutate(percentage = state_value/total_value*100) %>% 
  #Only show results for spring
  filter(str_detect(region,"Spring"))

quota_df <- quota_allocation %>% 
  left_join(historic_spp) %>% 
  group_by(state,abrev,year,region,spp,quota) %>% 
  summarise(state_value = sum(value,na.rm= T), .groups = "drop") %>% 
  left_join(total_fited,
            by = c("year","region","spp")) %>%
  mutate(Distribution = state_value/total_value*100,
         Historic = quota*100) %>% 
  group_by(state,quota,spp) %>% 
  mutate(RMean = zoo::rollmean(x = Distribution, 
                            10,
                            fill = NA,
                            na.rm=T)
    ) %>% 
  #Only show results for spring
  filter(str_detect(region,"Spring"),
         !is.na(RMean) # Remove NAs from rollmean
         ) %>%  
  left_join(state_lat) %>% 
  filter(
    # spp =="Centropristis striata"
    spp %in% quota_allocation$spp
  )

head(quota_df) %>% 
  kable()

Exploring different ways to show the results

Difference line plot

This version shows the difference between the Historic quota allocation and the distribution proportion of the stock:

  • diff < 0 = the distribution proportion is larger than the allocated quota
  • diff > 0 = the distribution proportion is smaller than the allocated quota
# Option one

quota_df %>%
  mutate(diff = Historic- Distribution,
         diff_rmean = RMean- Distribution) %>% 
  gather("type","value",diff:diff_rmean) %>% 
  # View()
  ggplot() +
  geom_line(
    aes(
      x = year,
      y = value,
      color = order
    )
  ) +
  scale_color_manual("State",
    values = state_pallet,
    labels = quota_df %>% arrange(order) %>%  pull(state) %>% unique()
    ) +
  facet_grid(type~spp, 
             scales = "free") +
  theme_dark()

Linetype plot

Here, we plot the distributional quota (solid lines) with each State’s allocation with dashed (—-) lines

# Option one

quota_df %>% 
  gather("level","quota",Distribution:RMean) %>% 
  # mutate(diff = quota_per- percentage) %>% 
  # View()
  ggplot() +
  geom_line(
    aes(
      x = year,
      y = quota,
      color = order
    )
  ) +
  labs(x = "Year",y = "Quota (%)") +
  scale_fill_manual("State",
    values = state_pallet,
    labels = quota_df %>% arrange(order) %>%  pull(state) %>% unique()
    ) +
  scale_color_manual("State",
    values = state_pallet,
    labels = quota_df %>% arrange(order) %>%  pull(state) %>% unique()
    ) +
  scale_linetype("Quota") +
  facet_grid(spp ~ level)+
  theme_dark()

Efficiency index

The idea here is create and efficiency index (Danger!) that computes the alignment between the distribution and the actual allocation. The index is simply;

\[ei = \frac{HistoricQuota}{DistributionProportion}\] So, in cases where ei = 1, the quota is aligned with the distribution; when ei > 1 then the historic quota is more than the stock’s State’s distribution, contrarily, ei < 1 means that the historic quota is less than what the State currently has.

Note: - There are some crazzy outliers that have been removed, for now… - Bottom plot representing index as a Rmean

As a normal year to year
# Option one

eff_index <- quota_df %>% 
  # filter(
  #   spp =="Centropristis striata"
  # ) %>% 
  mutate(index = Distribution/Historic,
         index_rmean = RMean/Historic) %>%
  gather("level","index",index:index_rmean) %>%
  filter(index < 5) # there are some craaaazy outliers
  # View()
  
ggplot(eff_index) +
  geom_line(
    aes(
      x = year,
      y = index,
      color = state
    ),
  ) +
  labs(x = "Year",y = "Efficiency index") +
  scale_fill_manual("State",
    values = state_pallet,
    labels = quota_df %>% arrange(order) %>%  pull(state) %>% unique()
    ) +
  scale_color_manual("State",
    values = state_pallet,
    labels = quota_df %>% arrange(order) %>%  pull(state) %>% unique()
    ) +
  facet_grid(level~spp,
             scales = "free")+
  theme_dark()

NOAAs port approach

Dynamic figure: Aggregated Proportional change per survey


total_fited <- historic_spp %>% 
  group_by(year,region,spatial) %>% 
  summarise(total_value = sum(value,na.rm=T),.groups = "drop")


state_fit <- historic_spp %>% 
  group_by(state,year,region,spatial) %>% 
  summarise(state_value = sum(value,na.rm= T), .groups = "drop") %>% 
  left_join(total_fited,
            by = c("year","region","spatial")) %>%
  mutate(percentage = state_value/total_value*100) %>% 
  left_join(periods,
            by = "year") %>% 
  group_by(state,order,label,region,spatial) %>% 
  summarise(mean_per = round(mean(percentage)),.groups = "drop")

# check percentages
# state_fit %>% 
#   group_by(period) %>% 
#   summarise(sum(mean_per))


p <- land_sf %>% 
  left_join(state_fit,
            by = "state") %>% 
  ggplot() +
  # geom_sf(aes(fill = mean_per)) +
  geom_sf(aes(fill = mean_per, text = paste(state, mean_per,"% of proportion"))) +
  viridis::scale_fill_viridis("Average proportion per State", alpha = 0.8) +
  facet_wrap(~ region + label +spatial, 
             nrow = 2) +
  labs(x = "Latitude", 
       y = "Longitude") +
  my_ggtheme_p(facet_tx_s = 12,
               leg_pos = "bottom") +
  theme(legend.key.width = unit(1,"line")) +
  theme_dark()

ggplotly(p,
         tooltip = "text",
         dynamicTicks = FALSE) %>% 
    style(hoverlabel = list(bgcolor = "white"), hoveron = "fill")
total_fited <- historic_spp %>%
  group_by(year,region,spp,spatial) %>%
  summarise(total_value = sum(value,na.rm=T),.groups = "drop")


state_change <-historic_spp %>% 
  group_by(state,year,region,spp,spatial) %>% 
  summarise(state_value = sum(value,na.rm= T), .groups = "drop") %>% 
  left_join(total_fited,
            by = c("year","region","spp","spatial")) %>%
  mutate(percentage = state_value/total_value*100,
         label = ifelse(year >= 1980 & year <= 2001,"Reference",
                         ifelse(year > 2001,"Today",NA)
                         )
         ) %>% 
  group_by(state,label,region,spp,spatial) %>% 
  summarise(mean_per = round(mean(percentage)),.groups = "drop") %>% 
  # Only show results for spring
  filter(str_detect(region,"Spring"),
         !is.na(label)
         ) %>% 
  select(-region) %>% 
  spread(label,mean_per) %>% 
  mutate(change = (Today-Reference)/(Today)*100,
         change = ifelse(change > 100,100,
                         ifelse(change < -100,-100,change)
         )
  ) %>%
  select(-4,-5) %>% 
  spread(spatial,change) %>% 
  mutate(
    #difference = (fp-sw)/((fp+sw)/2)*100,
    difference = abs(fp-sw)#,
         # difference = ifelse(difference > 100,100,
         #                     ifelse(difference < -100,-100,difference)
         # )
  ) %>% 
  gather("spatial","mean_per",fp:difference) %>% 
  mutate(
         spatial = ifelse(spatial == "fp","Fishing ports",
                          ifelse(spatial == "sw","State Waters","Difference")
         ),
         mean_per= replace_na(mean_per,0)# for those 0/0
  )
   

# The plot
prop_chng_map <- land_sf %>% 
  left_join(state_change,
            by = "state") %>% 
  filter(spatial != "Difference") %>% 
  ggplot() +
  geom_sf(aes(fill = mean_per)) +
  viridis::scale_fill_viridis("Change in proportion today\nrelative to 1980-2001\n(%)", alpha = 0.8,
                              limits = c(-100,100),
                              breaks = seq(-100,100,25),
                              labels = c("<-100",seq(-75,75,25),">100")
                              ) +
  facet_grid(spatial~ spp) +
  labs(x = "", 
       y = "") +
  my_ggtheme_p(facet_tx_s = 20,
               leg_pos = "bottom",
               axx_tx_ang = 45,
               ax_tx_s = 12,
               ax_tl_s = 18,
               hjust = 1) +
  theme(legend.key.width = unit(4,"line"),
        legend.title.align=0.5) 

# ggsave(filename = "temp_proportion_chng.jpg",
#          plot = prop_chng_map,
#          path = my_path("R","Figures"),
#          width = 10,
#          height = 10
#   )


#### Option with differences

prop_chng_map_diff <- land_sf %>% 
  left_join(state_change,
            by = "state") %>% 
  filter(spatial == "Difference") %>% 
  ggplot() +
  geom_sf(aes(fill = mean_per)) +
  viridis::scale_fill_viridis("Change in proportion today\nrelative to 1980-2001\n(%)", alpha = 0.8,
                              option = "C"
                              limits = c(-100,100),
                              breaks = seq(-100,100,25),
                              labels = c("<-100",seq(-75,75,25),">100")
                              ) +
  facet_grid(spatial~ spp) +
  labs(x = "", 
       y = "") +
  my_ggtheme_p(facet_tx_s = 20,
               leg_pos = "bottom",
               axx_tx_ang = 45,
               ax_tx_s = 12,
               ax_tl_s = 18,
               hjust = 1) +
  theme(legend.key.width = unit(4,"line"),
        legend.title.align=0.5,
        strip.background = element_blank(),
        strip.text.x = element_blank())


# Cowplot option
p <- ggdraw() +
  # Revenue circular
  draw_plot(prop_chng_map, x = 0, y = 0.25, width = 1, height = 0.65) +
  # Catch circular
  draw_plot(prop_chng_map_diff, x = 0.101, y = 0, width = 0.798, height = 0.4) +
  draw_plot_label(label = c("Latitude", "Longitude"), 
                  size = 16,
                  angle = c(90,0),
                  x = c(0.1,0.45), 
                  y = c(0.45,0.11)
  )
    

save_plot(
  path = my_path("R","Figures"),
  "proportion_chg_diffN.jpg",
  p,
  base_height = 14,
  base_width = 14
)

Proportion change realtive to past

total_fited <- historic_spp %>%
  group_by(year,season,spp,spatial) %>%
  summarise(total_value = sum(value,na.rm=T),.groups = "drop")


state_change <-historic_spp %>% 
  group_by(state,year,season,spp,spatial) %>% 
  summarise(state_value = sum(value,na.rm= T), .groups = "drop") %>% 
  left_join(total_fited,
            by = c("year","region","spp","spatial")) %>%
  mutate(percentage = state_value/total_value*100,
         label = ifelse(year >= 1980 & year <= 2001,"Reference",
                         ifelse(year > 2001,"Today",NA)
                         )
         ) %>% 
  group_by(state,label,region,spp,spatial) %>% 
  summarise(mean_per = round(mean(percentage)),.groups = "drop") %>% 
  # Only show results for spring
  filter(str_detect(region,"Spring"),
         !is.na(label)
         ) %>% 
  select(-region) %>% 
  spread(label,mean_per) %>% 
  mutate(change = (Today-Reference)/(Today)*100,
         change = ifelse(change > 100,100,
                         ifelse(change < -100,-100,change)
         )
  ) %>%
  select(-4,-5) %>% 
  spread(spatial,change) %>% 
  mutate(
    #difference = (fp-sw)/((fp+sw)/2)*100,
    difference = abs(fp-sw)#,
         # difference = ifelse(difference > 100,100,
         #                     ifelse(difference < -100,-100,difference)
         # )
  ) %>% 
  gather("spatial","mean_per",fp:difference) %>% 
  mutate(
         spatial = ifelse(spatial == "fp","Fishing ports",
                          ifelse(spatial == "sw","State Waters","Difference")
         ),
         mean_per= replace_na(mean_per,0)# for those 0/0
  )
   

# The plot
prop_chng_map <- land_sf %>% 
  left_join(state_change,
            by = "state") %>% 
  filter(spatial != "Difference") %>% 
  ggplot() +
  geom_sf(aes(fill = mean_per)) +
  viridis::scale_fill_viridis("Change in proportion today\nrelative to 1980-2001\n(%)", alpha = 0.8,
                              limits = c(-100,100),
                              breaks = seq(-100,100,25),
                              labels = c("<-100",seq(-75,75,25),">100")
                              ) +
  facet_grid(spatial~ spp) +
  labs(x = "", 
       y = "") +
  my_ggtheme_p(facet_tx_s = 20,
               leg_pos = "bottom",
               axx_tx_ang = 45,
               ax_tx_s = 12,
               ax_tl_s = 18,
               hjust = 1) +
  theme(legend.key.width = unit(4,"line"),
        legend.title.align=0.5) 

# ggsave(filename = "temp_proportion_chng.jpg",
#          plot = prop_chng_map,
#          path = my_path("R","Figures"),
#          width = 10,
#          height = 10
#   )


#### Option with differences

prop_chng_map_diff <- land_sf %>% 
  left_join(state_change,
            by = "state") %>% 
  filter(spatial == "Difference") %>% 
  ggplot() +
  geom_sf(aes(fill = mean_per)) +
  viridis::scale_fill_viridis("Change in proportion today\nrelative to 1980-2001\n(%)", alpha = 0.8,
                              option = "C"
                              limits = c(-100,100),
                              breaks = seq(-100,100,25),
                              labels = c("<-100",seq(-75,75,25),">100")
                              ) +
  facet_grid(spatial~ spp) +
  labs(x = "", 
       y = "") +
  my_ggtheme_p(facet_tx_s = 20,
               leg_pos = "bottom",
               axx_tx_ang = 45,
               ax_tx_s = 12,
               ax_tl_s = 18,
               hjust = 1) +
  theme(legend.key.width = unit(4,"line"),
        legend.title.align=0.5,
        strip.background = element_blank(),
        strip.text.x = element_blank())


# Cowplot option
p <- ggdraw() +
  # Revenue circular
  draw_plot(prop_chng_map, x = 0, y = 0.25, width = 1, height = 0.65) +
  # Catch circular
  draw_plot(prop_chng_map_diff, x = 0.101, y = 0, width = 0.798, height = 0.4) +
  draw_plot_label(label = c("Latitude", "Longitude"), 
                  size = 16,
                  angle = c(90,0),
                  x = c(0.1,0.45), 
                  y = c(0.45,0.11)
  )
    

save_plot(
  path = my_path("R","Figures"),
  "proportion_chg_diffN.jpg",
  p,
  base_height = 14,
  base_width = 14
)

Aggregated Proportional change


total_fited <- historic_spp %>%
  group_by(year,region,spatial) %>%
  summarise(total_value = sum(value,na.rm=T),.groups = "drop")


state_change <- historic_spp %>% 
  group_by(state,year,region,spatial) %>% 
  summarise(state_value = sum(value,na.rm= T), .groups = "drop") %>% 
  left_join(total_fited,
            by = c("year","region","spatial")) %>%
  mutate(percentage = state_value/total_value*100,
         label = ifelse(year >= 1980 & year <= 2001,"reference",
                         ifelse(year > 2001,"today",NA)
                         )
         ) %>% 
  # left_join(periods,
            # by = "year") %>% 
  group_by(state,label,region,spatial) %>% 
  summarise(mean_per = round(mean(percentage)),.groups = "drop") %>% 
  #Only show results for spring
  filter(#str_detect(region,"Spring"),
         !is.na(label)
         ) %>% 
  # select(-region) %>% 
  # Estimate percentage change
  spread(label,mean_per) %>% 
  mutate(raw_change = (today-reference)/(today)*100,
         change = ifelse(raw_change > 100,100,
                         ifelse(raw_change < -100,-100,raw_change)
         )
  ) %>%
  select(-reference,-today) 


#### Average
state_change %>% 
  mutate(
    wl = ifelse(change < 0, "L",
                ifelse(change == 0, "NC","W"))
  ) %>% 
  # View()
  # group_by(wl) %>% 
  group_by(region,spatial,wl) %>% 
  summarise(
    states = paste(unique(state),collapse = ", "),
    mean(raw_change),
    sd(raw_change)
  ) %>% 
  write_csv("../Results/state_relative_chng.csv")
  View()



  # Estimate spatial differences in percentage change
spatial_diff <- state_change %>% 
  spread(spatial,change) %>% 
  mutate(spatial_diff = abs(fp-sw)) %>% 
  select(state, category = region, diff = spatial_diff)

# Estimate seasonal differences in percentage change
season_diff <- state_change %>% 
  spread(region,change) %>%  
  mutate(season_diff = abs(`Northeast US Fall`-`Northeast US Spring`)) %>% 
  select(state,category = spatial,diff = season_diff)

differences <- season_diff %>% 
  bind_rows(spatial_diff) %>% 
  mutate(
    label = ifelse(category == "fp","Fishing ports",
                          ifelse(category == "sw","State Waters",category)
         )
  )

# For in text differences
differences %>% 
  group_by(category) %>%
  summarise_at(vars(diff),
    c(mean = mean,
      sd =sd,
      min = min,
      max= max))


# The main plot
prop_chng_map <- land_sf %>% 
  left_join(state_change,
            by = "state") %>% 
  # filter(spatial != "Difference" & cat != "difference_reg") %>% 
  ggplot() +
  geom_sf(aes(fill = change)) +
  viridis::scale_fill_viridis("Change in proportion today\n relative to 1973-1984\n(%)", alpha = 0.8,
                              limits = c(-100,100),
                              breaks = seq(-100,100,25),
                              labels = c(seq(-100,75,25),">100")
                              ) +
  facet_grid(spatial~ region) +
  labs(x = "", 
       y = "") +
  my_ggtheme_p(facet_tx_s = 20,
               leg_pos = "bottom",
               axx_tx_ang = 45,
               ax_tx_s = 12,
               ax_tl_s = 18,
               hjust = 1) +
  theme(legend.key.width = unit(4,"line"),
        legend.title.align=0.5,
        strip.text.y = element_blank(),
        strip.background = element_blank(),
        ) 

ggsave(filename = "proportion_chng_agg.png",
         plot = prop_chng_map,
         path = my_path("R","Figures"),
         width = 10,
         height = 10
  )


#### Option with differences

# Season differencce

spat_diff <- land_sf %>% 
  left_join(differences,
            by = "state") %>% 
  filter(!category %in% c("fp","sw")) %>% 
  ggplot() +
  geom_sf(aes(fill = diff)) +
  viridis::scale_fill_viridis("Differences", 
                              alpha = 0.8,
                              option = "C",
                              limits = c(0,50),
                              breaks = seq(0,50,10)
                              ) +
  facet_wrap(~ label,
             ncol = 2) +
  labs(x = "", 
       y = "") +
  my_ggtheme_p(facet_tx_s = 20,
               leg_pos = "bottom",
               axx_tx_ang = 45,
               ax_tx_s = 12,
               ax_tl_s = 18,
               hjust = 1) +
  theme(legend.key.width = unit(4,"line"),
        legend.title.align=0.5,
        strip.background = element_blank(),
        strip.text.x = element_blank())

ggsave(filename = "spat_diff.png",
         plot = spat_diff,
         path = my_path("R","Figures"),
         width = 8,
         height = 6
  )

# seasonal
seas_diff <- land_sf %>% 
  left_join(differences,
            by = "state") %>% 
  filter(category %in% c("fp","sw")) %>% 
  ggplot() +
  geom_sf(aes(fill = diff)) +
  viridis::scale_fill_viridis("Differences", 
                              alpha = 0.8,
                              option = "C",
                              limits = c(0,50),
                              breaks = seq(0,50,10)
                              ) +
  facet_wrap(~ label,
             ncol = 1,
             strip.position="right") +
  labs(x = "", 
       y = "") +
  my_ggtheme_p(facet_tx_s = 20,
               leg_pos = "",
               axx_tx_ang = 45,
               ax_tx_s = 12,
               ax_tl_s = 18,
               hjust = 1) +
  theme(strip.background = element_blank(),
        # strip.text.x = element_blank(),
        axis.text.y = element_blank(),
        axis.line.y = element_blank()
        )

ggsave(filename = "seas_diff.png",
         plot = seas_diff,
         path = my_path("R","Figures"),
         width = 8,
         height = 6
  )


### SRAH LANDING DATA
# read_excel_allsheets <- function(filename, tibble = TRUE) {
#     # I prefer straight data.frames
#     # but if you like tidyverse tibbles (the default with read_excel)
#     # then just pass tibble = TRUE
#     sheets <- readxl::excel_sheets(filename)[2:8]
#     x <- lapply(sheets, function(X) readxl::read_excel(filename, sheet = X))
#     if(!tibble) x <- lapply(x, as.data.frame)
#     names(x) <- sheets
#     x
# }
# Get data path
# ports_path <- my_path("D","NOAA", name = "SSmith_2015-2021 Landings_JUN 2021.xlsx")

# Load ports
# ports_data <- bind_rows(read_excel_allsheets(ports_path)) %>%
#   clean_names() %>%
#   mutate_if(is.character,
#               ~ str_to_lower(.)) %>%
#     filter(species_name %in% c("summer flounder","black sea bass","scup"))
LS0tCnRpdGxlOiAiU3BhdGlhbCBBbmFseXNpcyIKYXV0aG9yOiAiSnVsaWFubyBQYWxhY2lvcyBBYnJhbnRlcyIKb3V0cHV0OgogICMgaHRtbF9kb2N1bWVudDoKICBodG1sX25vdGVib29rOgogICAgZmlnX3dpZHRoOiA2CiAgICBmaWdfaGVpZ2h0OiA0CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDYKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgdGhlbWU6IGRhcmtseQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KE15RnVuY3Rpb25zKQpNeUZ1bmN0aW9uczo6bXlfbGliKGMoImdnbWFwIiwic2YiLCJzdCIsInRpZHl2ZXJzZSIsInRvb2xzIiwicmVhZHIiLCJkYXRhLnRhYmxlIiwibWFwcyIsInZpcmlkaXMiLCJ3ZXNhbmRlcnNvbiIsImtuaXRyIiwia2FibGVFeHRyYSIsInBsb3RseSIsImdncmVwZWwiLCJnZ3NmbGFiZWwiLCJqYW5pdG9yIiwiaW50ZXJwIiwicm5hdHVyYWxlYXJ0aCIsInJlYWR4bCIsImNvd3Bsb3QiKSkKCiMgRml4IG5ldyB1cGRhdGVzIG9mIHNmIHBhY2thZ2UKc2Y6OnNmX3VzZV9zMih1c2VfczIgPSBGQUxTRSkKCgojIENyZWF0ZSBzcGVjaWZpYyBzdGF0ZSBwYWxsZXQgZnJvbSBvdXIgZnJpZW5kIFdlcyBBbmRlcnNzb24Kc3RhdGVfcGFsbGV0IDwtIGMod2VzX3BhbGV0dGUobiA9IDUsIG5hbWUgPSAiRGFyamVlbGluZzEiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdlc19wYWxldHRlKG4gPSA1LCBuYW1lID0gIkRhcmplZWxpbmcyIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3ZXNfcGFsZXR0ZShuID0gMywgbmFtZSA9ICJSb3lhbDEiKQogICAgICAgICAgICAgICAgICApCgpgYGAKCiMgTWV0aG9kcwoKIyMgU3BhdGlhbCBkYXRhIHByZXBhcmF0aW9uCgojIyMgTG9hZCBkYXRhCgojIyMjIE1hcHMgZGF0YQoKV2UgdXNlIHRocmVlIGRpZmZlcmVudCBzaGFwZWZpbGVzIGZvciB0aGUgY29udGluZW50YWwgVS5TLiBsYW5kIG1hc3MsIHRoZSBTdGF0ZSB3YXRlcnMgb2YgbWFpbmUsIG5ldyBoYW1wc2hpcmUsIG1hc3NhY2h1c2V0cywgY29ubmVjdGljdXQsIHJob2RlIGlzbGFuZCwgbmV3IHlvcmssIG5ldyBqZXJzZXksIGRlbGF3YXJlLCBtYXJ5bGFuZCwgdmlyZ2luaWEsIG5vcnRoIGNhcm9saW5hIGFuZCB0aGUgTm9ydGggRWFzdCBFRVouIE1vcmVvdmVyLCB3ZSB1c2UgdGhlIE5PQUEgZGF0YXNldCBvZiBsYW5kaW5ncyBwZXIgcG9ydC4KCiMjIyMjIDEuLSBMYW5kIHNoYXBlZmlsZQoKQ292ZXJzIHRoZSBVUyBsYW5kIHRlcnJpdG9yeSBmb3IgdmlzdWFsaXphdGlvbi4gRGF0YSBwcm92aWRlZCBmcm9tIHRoZSBgbWFwYCBwYWNrYWdlLgoKCmBgYHtyIGxhbmRfc2YsIGV2YWwgPSBULCBlY2hvID0gVCwgcmVzdWx0cyA9ICdoaWRlJ30KClN0YXRlcyA8LSBjKCJtYWluZSIsICJuZXcgaGFtcHNoaXJlIiwgIm1hc3NhY2h1c2V0dHMiLCAiY29ubmVjdGljdXQiLCAicmhvZGUgaXNsYW5kIiwgIm5ldyB5b3JrIiwgIm5ldyBqZXJzZXkiLCAiZGVsYXdhcmUiLCAibWFyeWxhbmQiLCAidmlyZ2luaWEiLCAibm9ydGggY2Fyb2xpbmEiKSAKCiMgLS0tLS0tLS0tLS0tLS0gIwojIFVTIFN0YXRlIE1hcCAobGFuZCkKIyAtLS0tLS0tLS0tLS0tLSAjCgpsYW5kX3NmIDwtIHN0X2FzX3NmKG1hcCgic3RhdGUiLCBwbG90ID0gRkFMU0UsIGZpbGwgPSBUUlVFKSkgJT4lIAogIGZpbHRlcihJRCAlaW4lIFN0YXRlcykgJT4lIAogIG11dGF0ZShhYnJldiA9IGMoIkNUIiwiREUiLCJNRSIsIk1EIiwiTUEiLCJOSCIsIk5KIiwiTlkiLCJOQyIsIlJJIiwiVkEiKSwKICAgICAgICAgc3RhdGUgPSBzdHJfdG9fc2VudGVuY2UoSUQpCiAgICAgICAgICkKCiMgVmlzdWFsIGV4cGxvcmF0aW9uIChvLmshICkKZ2dwbG90KGxhbmRfc2YpICsKICBnZW9tX3NmKGFlcyhmaWxsID0gc3RhdGUpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gc3RhdGVfcGFsbGV0KSArCiAgdGhlbWVfZGFyaygpCiAgICAgICAgICAKCmBgYAoKIyMjIyMgIDIuLSBFRVogc2hhcGVmaWxlCgpVc2VkIHRoZSAqU2VhIEFyb3VuZCBVcyogc2hhcGVmbGUgdXBkYXRlZCB0byBKdW5lIDIwMTYuCgpgYGB7ciBlZXpfc2YsIGV2YWwgPSBULCBlY2hvID0gVH0KCiMgVVMgRUVaIG1hcApwYXRoX3dvcmxkIDwtIG15X3BhdGgoIkciLCBleHRyYV9wYXRoID0gIlNwYXRpYWwvU0FVL1NBVV9TaGFwZWZpbGUiLCBuYW1lID0gIlNBVUVFWl9KdWx5MjAxNS5zaHAiKQoKIyBMb2FkIGl0IQplZXpfc2YgPC0gc3RfcmVhZChwYXRoX3dvcmxkKSAlPiUKICByZW5hbWUoZWV6X25hbWUgPSBOYW1lKSAlPiUKICBzdF90cmFuc2Zvcm0oY3JzID0gNDMyNikgJT4lICMgNDMyNgogIGZpbHRlcihlZXpfbmFtZSA9PSAiVVNBIChFYXN0IENvYXN0KSIpICU+JQogIHN0X3NpbXBsaWZ5KHByZXNlcnZlVG9wb2xvZ3kgPSBUUlVFLCBkVG9sZXJhbmNlID0gMC4xKSAjMC4xIGZvciBwYXBlcgoKIyBWaXN1YWwgZXhwbG9yYXRpb24gKG8uayEgKQpnZ3Bsb3QoZWV6X3NmKSArCiAgZ2VvbV9zZigpICsKICB0aGVtZV9kYXJrKCkKCmBgYAoKIyMjIyMgIDMuLSAgU3RhdGUgd2F0ZXJzCgpDb3ZlcnMgdGhlIHN0YXRlIHdhdGVycyBvZiB0aGUgTkUgVVMgc3RhdGVzLiBEYXRhIGZyb20gW2RhdGEuZ292XShodHRwczovL2NhdGFsb2cuZGF0YS5nb3YvZGF0YXNldC9mZWRlcmFsLWFuZC1zdGF0ZS13YXRlcnMpLiAgCgoqTGljZW5zZTogTm8gbGljZW5zZSBpbmZvcm1hdGlvbiB3YXMgcHJvdmlkZWQuIElmIHRoaXMgd29yayB3YXMgcHJlcGFyZWQgYnkgYW4gb2ZmaWNlciBvciBlbXBsb3llZSBvZiB0aGUgVW5pdGVkIFN0YXRlcyBnb3Zlcm5tZW50IGFzIHBhcnQgb2YgdGhhdCBwZXJzb24ncyBvZmZpY2lhbCBkdXRpZXMgaXQgaXMgY29uc2lkZXJlZCBhIFUuUy4gR292ZXJubWVudCBXb3JrLioKCmBgYHtyIHN0YXRlX3NmLCBldmFsID0gVCwgZWNobyA9IFR9CgoKc3RhdGVfc2YgPC0gIHN0X3JlYWQoIn4vT25lRHJpdmUgLSBVVy1NYWRpc29uL0ZlZGVyYWxBbmRTdGF0ZVdhdGVycy9GZWRlcmFsQW5kU3RhdGVXYXRlcnMuZ2RiIikgJT4lCiAgamFuaXRvcjo6Y2xlYW5fbmFtZXMoKSAlPiUgCiAgbXV0YXRlKGp1cmlzZGljdGkgPSBzdHJfdG9fbG93ZXIoanVyaXNkaWN0aSkpICU+JSAKICBmaWx0ZXIoanVyaXNkaWN0aSAlaW4lIFN0YXRlcykgJT4lIAogIG11dGF0ZShzdGF0ZSA9IHN0cl90b19zZW50ZW5jZShqdXJpc2RpY3RpKSkgJT4lIAogIHN0X3RyYW5zZm9ybShjcnMgPSA0MzI2KSAlPiUgICAjIGZvciBtYXRjaGluZyBwcm9qZWN0aW9ucwogIHN0X3NpbXBsaWZ5KHByZXNlcnZlVG9wb2xvZ3kgPSBUUlVFLCBkVG9sZXJhbmNlID0gMTAwMDApICMwLjEgZm9yIHBhcGVyCgoKIyBWaXN1YWwgZXhwbG9yYXRpb24gKG8uayEgKQpnZ3Bsb3Qoc3RhdGVfc2YpICsKICBnZW9tX3NmKGFlcyhmaWxsID0gc3RhdGUpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gc3RhdGVfcGFsbGV0KSArCiAgdGhlbWVfZGFyaygpCgpgYGAKCiMjIyMjIDQuLSBGaXNoaW5nIHBvcnRzCgojIyMjIyMgNC4xIE5PQUEncyBkYXRhCgpEYXRhc2V0IHByb3ZpZGVyOiBKb2UgTXllcnMgSm9zZXBoLk15ZXJzQGFjY3NwLm9yZyBOT0FBCgpOb24tY29uZmlkZW50aWFsIGRhdGFzZXQgY29udGFpbmluZyBhbm51YWwgbGFuZGluZ3MvdmFsdWUgc3VtbWFyaWVzIGJ5IHBvcnQgZm9yIGJsYWNrIHNlYSBiYXNzLCBzY3VwIGFuZCBzdW1tZXIgZmxvdW5kZXIsIGZyb20gTkMtTUUgZm9yIDE5NzAtMjAyMC4gCgpJbiBvcmRlciB0byBtYWtlIHRoZSByZXBvcnQgbm9uLWNvbmZpZGVudGlhbCwgSSBhbSBkaXNwbGF5aW5nIGFzIG11Y2ggb2YgdGhlIHBvcnQtbGV2ZWwgc3VtbWFyeSBkYXRhIGFzIEkgY2FuIOKAkyBhbmQgZm9yIGNhc2VzIHdoZXJlIHRoZSBwb3J0LWxldmVsIHdhcyBjb25maWRlbnRpYWwsIEkgaGF2ZSBmaXJzdCBhdHRlbXB0ZWQgdG8gcm9sbC11cCBhbnkgY29uZmlkZW50aWFsIHBvcnQtbGV2ZWwgc3VtbWFyaWVzIGludG8gc3RhdGUtbGV2ZWwgc3VtbWFyaWVzIHdpdGhpbiB0aGUgc2FtZSB5ZWFyLiAgSWYgdGhvc2Ugc3RhdGUtbGV2ZWwgc3VtbWFyaWVzIGNvbnRpbnVlIHRvIGJlIGNvbmZpZGVudGlhbCwgSSBoYXZlIGZ1cnRoZXIgcm9sbGVkLXVwIHRob3NlIGNvbmZpZGVudGlhbCBwb3J0cyBhY3Jvc3Mgc3RhdGVzIGludG8gYSBjb2FzdC1sZXZlbCBzdW1tYXJ5LiAgRXZlbiBhdCB0aGUgY29hc3QgbGV2ZWwsIHRoZXJlIHdlcmUgc2V2ZXJhbCBjYXNlcyB3aGVyZSBub3QgZW5vdWdoIGNvbmZpZGVudGlhbCBwb3J0cyBjb3VsZCBiZSBjb21iaW5lZCB0byBwcm9kdWNlIGEgbm9uLWNvbmZpZGVudGlhbCBzdW1tYXJ5IOKAkyBhbmQgc28gZm9yIHRob3NlIHJvd3MgaXQgd2FzIG5lY2Vzc2FyeSB0byByZWRhY3QgdGhlIGZpbmFsIGxhbmRpbmdzL3ZhbHVlIGRhdGEuICBGb3J0dW5hdGVseSwgdGhpcyBvbmx5IGFtb3VudHMgdG8gbGVzcyB0aGFuIDAuNSUgb2YgdGhlIHRvdGFsIGxhbmRpbmdzIGRhdGEgKGNoYXJhY3Rlcml6ZWQgaW4gdGhlIOKAnFBpdm90IGJ5IENvbmZpZGVudGlhbGl0eeKAnSB0YWIgb2YgdGhlIHNwcmVhZHNoZWV0KS4KCgoqTGljZW5zZT8/Py4qCgpgYGB7cn0KIyBOT0FBIERBVEEKCnBvcnRzX3BhdGggPC0gbXlfcGF0aCgiRCIsIk5PQUEiLCBuYW1lID0gIlBhbGFjaW9zSiAtIEJTQiwgU0Zsb3VuZGVyLCBTY3VwIGJ5IFBvcnQgMTk3MC0yMDIwIC0gMjAyMS4xMC4yNS54bHN4IikKCgojIExvYWQgcG9ydHMKcG9ydHNfZGF0YSA8LSByZWFkX2V4Y2VsKHBvcnRzX3BhdGgsc2hlZXQgPSAyKSAlPiUgCiAgY2xlYW5fbmFtZXMoKSAlPiUKICBtdXRhdGVfaWYoaXMuY2hhcmFjdGVyLAogICAgICAgICAgICB+IHN0cl90b19sb3dlciguKQogICkgJT4lIAogIG11dGF0ZSgKICAgIHNwZWNpZXNfbmFtZSA9IGlmZWxzZShzdHJfZGV0ZWN0KGNvbW1vbl9uYW1lLCJibGFjayIpLCJibGFjayBzZWEgYmFzcyIsCiAgICAgICAgICAgICAgICAgaWZlbHNlKHN0cl9kZXRlY3QoY29tbW9uX25hbWUsInN1bW1lciIpLCJzdW1tZXIgZmxvdW5kZXIiLAogICAgICAgICAgICAgICAgICAgICAgICBjb21tb25fbmFtZSkKICAgICksCiAgICB0b3RhbF9saXZlX3BvdW5kcyA9IGFzLm51bWVyaWModG90YWxfbGl2ZV9wb3VuZHMpLAogICAgdG90YWxfdmFsdWUgPSBhcy5udW1lcmljKHRvdGFsX3ZhbHVlKQogICkgJT4lIAogIGZpbHRlcigKICAgICFwb3J0X25hbWUgJWluJSBjKCIqKnJvbGwtdXAgdG8gc3RhdGUtd2lkZSoqIiwiKipyb2xsLXVwIHRvIGNvYXN0LXdpZGUqKiIsInVua25vd24iKQogICkKYGBgCgoKIyMjIyMjIDQuMS4xIFRvcCBwb3J0cwoKYGBge3J9CiMgR2V0IG51bWJlciBvZiBwb3J0cyBpbiB0aGUgTk9BQSBkYXRhYmFzZQpvdmVyYWxsX3BvcnRfZGF0YSA8LSBwb3J0c19kYXRhICU+JQogIGZpbHRlcih5ZWFyID49IDIwMTAgJiB5ZWFyIDw9IDIwMTkpICU+JSAKICBncm91cF9ieShzcGVjaWVzX25hbWUscG9ydF9uYW1lLHN0YXRlX3Bvc3RhbCkgJT4lIAogIHN1bW1hcmlzZSgKICAgIHllYXJfdG9uID0gc3VtKHRvdGFsX2xpdmVfcG91bmRzKSwKICAgIHllYXJfdmFsdWUgPSBzdW0odG90YWxfdmFsdWUpCiAgKSAKCgp0b3BfcG9ydHMgPC0gYmluZF9yb3dzKAogICMgNzV0aCBwZXJjZW50aWxlIHVzZWQgaW4gcHJvamVjdAogIG92ZXJhbGxfcG9ydF9kYXRhICU+JSAKICAgIGdyb3VwX2J5KHNwZWNpZXNfbmFtZSkgJT4lIAogICAgdG9wX2ZyYWMoMC4yNSx5ZWFyX3RvbikgJT4lICAjIHRvcCA3NQogICAgbXV0YXRlKHRyZXNoID0gIjc1dGgiKSwKICAjIC0tLS0tLS0tLS0tLS0tLS0tLS0tICMKICAjIEZvciBzZW5zaXRpdml0eSB2YWx1ZXMKICAjIC0tLS0tLS0tLS0tLS0tLS0tLS0tICMKICAjIDk1JQogIG92ZXJhbGxfcG9ydF9kYXRhICU+JSAKICAgIGdyb3VwX2J5KHNwZWNpZXNfbmFtZSkgJT4lIAogICAgdG9wX2ZyYWMoMC41LHllYXJfdG9uKSAlPiUgIAogICAgbXV0YXRlKHRyZXNoID0gIjk1dGgiKSwKICAjIDg1JQogIG92ZXJhbGxfcG9ydF9kYXRhICU+JSAKICAgIGdyb3VwX2J5KHNwZWNpZXNfbmFtZSkgJT4lIAogICAgdG9wX2ZyYWMoMC4xNSx5ZWFyX3RvbikgJT4lIAogICAgbXV0YXRlKHRyZXNoID0gIjg1dGgiKSwKICAjIDY1JQogIG92ZXJhbGxfcG9ydF9kYXRhICU+JSAKICAgIGdyb3VwX2J5KHNwZWNpZXNfbmFtZSkgJT4lIAogICAgdG9wX2ZyYWMoMC4zNSx5ZWFyX3RvbikgJT4lICAjIHRvcCA3NQogICAgbXV0YXRlKHRyZXNoID0gIjY1dGgiKSwKICAjIDUwJQogIG92ZXJhbGxfcG9ydF9kYXRhICU+JSAKICAgIGdyb3VwX2J5KHNwZWNpZXNfbmFtZSkgJT4lIAogICAgdG9wX2ZyYWMoMC41LHllYXJfdG9uKSAlPiUgICMgdG9wIDc1CiAgICBtdXRhdGUodHJlc2ggPSAiNTB0aCIpCikKICAKYGBgCgojIyMjIyMgNC4xLjIgUG9ydHMgY29vcmRpbmF0ZXMKCgpgYGB7ciBzYXJhaHNfd29yZF9kYXRhfQogCm5vYWFfcG9ydHMgPC0gZGF0YS50YWJsZSgKICBwb3J0ID1zdHJfdG9fc2VudGVuY2UoYygKICAgICJQT0lOVCBKVURJVEgsIFJJIiwgIzQxLjM1OTkwNzkxNDU1MzU3NCwtNzEuNDgzMjMyNTA4NzIxODcsCiAgICAiQkVBVUZPUlQsIE5DIiwgIzM0LjcxMzg4Nzk2NTQwNTQsLTc2LjY2MjM5NjMwMTE3OTIxLAogICAgIkhBTVBUT04sIFZBIiwgIzM2Ljk4NjAwMzY2NzczMzI3LCAtNzYuMzUwMzgzMDY4NTk1NDUsCiAgICAiUE9JTlQgUExFQVNBTlQsIE5KIiwgIzQwLjA4MzUxODQ3Njc1MTAyLC03My45OTE5MDA5NDExMDY3OSwKICAgICJORVdQT1JUIE5FV1MsIFZBIiwgIzM3LjAwOTMzOTE5Mjk1MTgzLCAtNzYuNDg1NjU4NjI2MTMxNjgsCiAgICAiQkVMRk9SRCwgTkoiLCAjIDQwLjQzOTE4Nzg0NzM0MDI0LCAtNzQuMDc2MzA1NDg5OTQ2MgogICAgIk1PTlRBVUssIE5ZIiwgIzQxLjA3MzQyMjYyODY4MDM4LCAtNzEuOTM1ODU4MzYwODg4MTMKICAgICJIT0JVQ0tFTiwgTkMiLCAjMzQuOTQ4NDQ1Njc5ODIzODQsIC03Ni43NDMzMzQxOTU2MDQyNQogICAgIldBTkNIRVNFLCBOQyIsICMzNS44MzUyNDk4NDU1MDMzNCwgLTc1LjYxMTIxNjcxNzIyOTIxCiAgICAiTkVXIEJFREZPUkQsIE1BIiwgIyA0MS42MzA0OTQwNTIzMjYzMDYsIC03MC45MTU4MDY2OTEzNDA1NQogICAgIkNBUEUgTUFZLCBOSiIsICMgMzguOTQ5Nzk3MTkxMjY1MDgsIC03NC45MDI4MDk0NDc5MDQ2MwogICAgIk9SSUVOVEFMLCBOQyIsICMgMzUuMDEzNTcxMDg0MzczMTI2LCAtNzYuNjY3OTMxMTQzMzM3MDQKICAgICJDSElOQ09URUFHVUUsIFZBIiwgIyAzNy45MTc4ODA5NDA3MDIwNCwgLTc1LjM1OTQ3NTgwNDc4MjE5CiAgICAiRU5HRUxIQVJELCBOQyIsICMgMzUuMjYyOTI5MjQzMTE4Nzc2LCAtNzYuMDg2ODA0NTI2NzA1MDgKICAgICJTVE9OSU5HVE9OLCBDVCIsICMgNDEuMzI3MjgyMjA0NDg0MDM1LCAtNzEuOTIyMzcyMTM1OTI1MQogICAgIkxPTkcgQkVBQ0gvQkFSTkVHQVQgTElHSFQsIE5KIiwgIzM5Ljc1Mjg1NTkyOTkwMDQ4NCwgLTc0LjExMzI5MzEwMTE1OTAyCiAgICAiT0NFQU4gQ0lUWSBoYXJib3IsIE1EIiwgIzM4LjM4MDI5MjIwMDQ4NTksIC03NS4wNTA4OTczNjkyMDMxOAogICAgIyBNYW51YWxseSBpbmNsdWRlZCB0aGVzZSBwb3J0cyBhcyB0b3AgU3RhdGUgcG9ydHMgZnJvbSBOT0FBCiAgICAiSW5kaWFuIHJpdmVyLCBERSIsCiAgICAiUG9ydGxhbmQsIE1FIiwgIzQzLjY2MzQ0Nzk0NzI4OTkyLCAtNzAuMjI5Mzc1NTQzNzg4ODUKICAgICJQb3J0c21vdXRoLCBOSCIsICM0My4wNTMzNDY5NDIwMzk1MywgLTcwLjcxMjY3NjA4MzM3MTQKICAgICMgTW9yZSBwb3J0cwogICAgIkNoaW5jb3RlYWd1ZSwgVkEiLCAjIDM3Ljk0Mjk1ODk2MzAyNDY1LCAtNzUuMzg0MTU2Njg1Nzk4ODcKICAgICJzZWEgaXNsZSBjaXR5LE5KICIsICMgMzkuMTQ5MTI2NTYzMjM4NTQsIC03NC42ODc5NzIwMjg0Nzg3MQogICAgImxld2VzLCBERSwgIiwgIyAzOC43ODk0MzY0MDk5MDU0MiwgLTc1LjA2MzQzNjkyNjEwODUxCiAgICAidmlyZ2luaWEgYmVhY2gsIFZBIiwgIyAzNi44NTkzNDMzODU3MjI1MDQsIC03NS45NDMyODM5ODE0MDA2NQogICAgImhhbXB0b24gYmF5cywgbnkiLCAjNDAuODQyMjkwNDAxODkyMDQsIC03Mi41MDk4NzU0NDA0MDk5OQogICAgIm1hdHRpdHVjaywgbnkiLCAjIDQxLjA1MzQyODM2MTkyMjkzLCAtNzIuNTk4OTkyMTQyNTgyNjkKICAgICJsaXR0bGUgY29tcHRvbiwgcmkiLCAjIDQxLjQ3NjUxMDM0NjEyMTMsIC03MS4xOTQ3NDY0MTU3OTEwNwogICAgIm5ldyBsb25kb24sIENUIiwgIzQxLjM0MTU3NzIwNzQ2NzkxNCwgLTcyLjA4Mjk2OTcxMDY0ODkKICAgICJhbWFnYW5zZXR0LCBueSIsICMgNDAuOTYxNzMwMDg2MzM1NjksIC03Mi4xMTg3OTMwNjc0MDc5OAogICAgImJhcm5lZ2F0IGxpZ2h0LCBuaiIsICMzOS43NTI5MTE1MjY2MjM4MywgLTc0LjA5OTI3ODMxODY4MzA4CiAgICAiY2hhdGhhbSAoY2Vuc3VzIG5hbWUgZm9yIGNoYXRoYW0gY2VudGVyKSwgTUEiLCAjIDQxLjY1ODY5NTQyMTEyMjQ3NCwgLTY5Ljk1NDY2NDUyNTU2NDQ4CiAgICAiZGVubmlzLCBtYSIsICM0MS42NTEyMTAzNzI2Mzg3MywgLTcwLjEzMTkzNjYzNzk4NTA5CiAgICAiZmFsbW91dGggKGNlbnN1cyBuYW1lIGZvciBmYWxtb3V0aCBjZW50ZXIpLCBtYSIsICM0MS41Mzk1NjMyNzE0NjUyNiwgLTcwLjYwMDAxMzQwNzA5NjY1LAogICAgImZyZWVwb3J0LCBueSIsICM0MC42MjI0MjM4NzQ3MzEwOSwgLTczLjU5MTYyNTA5NDAyMjA4CiAgICAibmFudHVja2V0IChjZW5zdXMgbmFtZSBmb3IgbmFudHVja2V0IGNlbnRlciksIE1BIiwgIzQxLjI2NjE2MDg4MjEwOTg1LCAtNjkuOTU2MTcyNzcyNTc5ODUKICAgICJuZXdwb3J0LCBSSSIsCiAgICAicG9pbnQgbG9va291dCwgbnkiLCAjNDAuNTg3NjQ2MTM0OTU1ODc1LCAtNzMuNTc2Mzc0ODUxMjkyNwogICAgInNoaW5uZWNvY2sgaW5kaWFuIHJlc2VydmF0aW9uLCBueSIsICM0MC44NjU4NzM5ODM5Njg3NTQsIC03Mi40NDIwOTI5MTcyMDE4CiAgICAid2VzdHBvcnQsIG1hIgogICkpLAogIGxhdCA9IGMoCiAgICA0MS4zNTk5MDc5MTQ1NTM1NzQsCiAgICAzNC43MTM4ODc5NjU0MDU0LAogICAgMzYuOTg2MDAzNjY3NzMzMjcsIAogICAgNDAuMDgzNTE4NDc2NzUxMDIsCiAgICAzNy4wMDkzMzkxOTI5NTE4MywgCiAgICA0MC40MzkxODc4NDczNDAyNCwgCiAgICA0MS4wNzM0MjI2Mjg2ODAzOCwKICAgIDM0Ljk0ODQ0NTY3OTgyMzg0LCAKICAgIDM1LjgzNTI0OTg0NTUwMzM0LAogICAgNDEuNjMwNDk0MDUyMzI2MzA2LAogICAgMzguOTQ5Nzk3MTkxMjY1MDgsCiAgICAzNS4wMTM1NzEwODQzNzMxMjYsCiAgICAzNy45MTc4ODA5NDA3MDIwNCwgCiAgICAzNS4yNjI5MjkyNDMxMTg3NzYsIAogICAgNDEuMzI3MjgyMjA0NDg0MDM1LCAKICAgIDM5Ljc1Mjg1NTkyOTkwMDQ4NCwgCiAgICAzOC4zODAyOTIyMDA0ODU5LAogICAgMzguNjIxMTM1OTM0MDM3NDYsCiAgICA0My42NjM0NDc5NDcyODk5MiwKICAgIDQzLjA1MzM0Njk0MjAzOTUzLAogICAgMzcuOTQyOTU4OTYzMDI0NjUsCiAgICAzOS4xNDkxMjY1NjMyMzg1NCwKICAgIDM4Ljc4OTQzNjQwOTkwNTQyLAogICAgMzYuODU5MzQzMzg1NzIyNTA0LAogICAgNDAuODQyMjkwNDAxODkyMDQsCiAgICA0MS4wNTM0MjgzNjE5MjI5MywKICAgIDQxLjQ3NjUxMDM0NjEyMTMsIAogICAgNDEuMzQxNTc3MjA3NDY3OTE0LAogICAgNDAuOTYxNzMwMDg2MzM1NjksIAogICAgMzkuNzUyOTExNTI2NjIzODMsIAogICAgNDEuNjU4Njk1NDIxMTIyNDc0LAogICAgNDEuNjUxMjEwMzcyNjM4NzMsIAogICAgNDEuNTM5NTYzMjcxNDY1MjYsIAogICAgNDAuNjIyNDIzODc0NzMxMDksCiAgICA0MS4yNjYxNjA4ODIxMDk4NSwgCiAgICA0MS40ODU1MTQzNDY2ODM5NTYsCiAgICA0MC41ODc2NDYxMzQ5NTU4NzUsCiAgICA0MC44NjU4NzM5ODM5Njg3NTQsCiAgICA0MS40OTI2Nzg3NTc0Njg3MwogICksCiAgbG9uID0gYygKICAgIC03MS40ODMyMzI1MDg3MjE4NywKICAgIC03Ni42NjIzOTYzMDExNzkyMSwKICAgIC03Ni4zNTAzODMwNjg1OTU0NSwKICAgIC03My45OTE5MDA5NDExMDY3OSwKICAgIC03Ni40ODU2NTg2MjYxMzE2OCwKICAgIC03NC4wNzYzMDU0ODk5NDYyLAogICAgLTcxLjkzNTg1ODM2MDg4ODEzLAogICAgLTc2Ljc0MzMzNDE5NTYwNDI1LAogICAgLTc1LjYxMTIxNjcxNzIyOTIxLAogICAgLTcwLjkxNTgwNjY5MTM0MDU1LAogICAgLTc0LjkwMjgwOTQ0NzkwNDYzLAogICAgLTc2LjY2NzkzMTE0MzMzNzA0LAogICAgLTc1LjM1OTQ3NTgwNDc4MjE5LAogICAgLTc2LjA4NjgwNDUyNjcwNTA4LAogICAgLTcxLjkyMjM3MjEzNTkyNTEsCiAgICAtNzQuMTEzMjkzMTAxMTU5MDIsCiAgICAtNzUuMDUwODk3MzY5MjAzMTgsCiAgICAtNzUuMDYzOTcwMjE3MTgzNDUsCiAgICAtNzAuMjI5Mzc1NTQzNzg4ODUsCiAgICAtNzAuNzEyNjc2MDgzMzcxNCwKICAgIC03NS4zODQxNTY2ODU3OTg4NywKICAgIC03NC42ODc5NzIwMjg0Nzg3MSwKICAgIC03NS4wNjM0MzY5MjYxMDg1MSwKICAgIC03NS45NDMyODM5ODE0MDA2NSwKICAgIC03Mi41MDk4NzU0NDA0MDk5OSwKICAgIC03Mi41OTg5OTIxNDI1ODI2OSwKICAgIC03MS4xOTQ3NDY0MTU3OTEwNywgCiAgICAtNzIuMDgyOTY5NzEwNjQ4OSwKICAgIC03Mi4xMTg3OTMwNjc0MDc5OCwKICAgIC03NC4wOTkyNzgzMTg2ODMwOCwKICAgICAtNjkuOTU0NjY0NTI1NTY0NDgsCiAgICAtNzAuMTMxOTM2NjM3OTg1MDksCiAgICAtNzAuNjAwMDEzNDA3MDk2NjUsCiAgICAgLTczLjU5MTYyNTA5NDAyMjA4LAogICAgLTY5Ljk1NjE3Mjc3MjU3OTg1LAogICAgIC03MS4zMjI2MzMyNjk3NTEyMiwKICAgICAtNzMuNTc2Mzc0ODUxMjkyNywKICAgICAtNzIuNDQyMDkyOTE3MjAxOCwKICAgIC03MS4wNTU1MTM0MjM5MjAzOQogICkKKSAlPiUgCiAgc2VwYXJhdGUocG9ydCwgaW50byA9IGMoInBvcnRfbmFtZSIsInN0YXRlX3Bvc3RhbCIpLCBzZXAgPSAnLCcpICU+JSAKICBtdXRhdGUocG9ydF9uYW1lID0gc3RyX3RvX2xvd2VyKHBvcnRfbmFtZSksCiAgICAgICAgIHN0YXRlX3Bvc3RhbCA9IHN0cl9zcXVpc2goc3RhdGVfcG9zdGFsKSkKICAKIyBJbmNsdWRlIGNvb3JkaW5hdGVzCm5vYWFfcG9ydHNfY29tcGxldGUgPC0gdG9wX3BvcnRzICU+JSAKICBsZWZ0X2pvaW4obm9hYV9wb3J0cywKICAgICAgICAgICAgIGJ5ID0gYygicG9ydF9uYW1lIiwgInN0YXRlX3Bvc3RhbCIpKSAlPiUgCiAgbXV0YXRlKAogICAgc3RhdGVfcG9zdGFsID0gc3RyX3RvX3VwcGVyKHN0YXRlX3Bvc3RhbCkKICApCiAgCiMgQ2hlY2sgZm9yIG1pc3NpbmcgcG9ydHMKbm9hYV9wb3J0c19jb21wbGV0ZSAlPiUgCiAgZmlsdGVyKHRyZXNoID09ICI3NXRoIiwKICAgIGlzLm5hKGxhdCkpICU+JSAKICBncm91cF9ieShwb3J0X25hbWUsc3RhdGVfcG9zdGFsKSAlPiUgCiAgc3VtbWFyaXNlKG4oKSkgJT4lIAogIFZpZXcoKQoKIyBTYXZlIGRhdGEgZm9yIGZ1dHVyZSBhbmFseXNpcwojIHdyaXRlX2Nzdihub2FhX3BvcnRzX2NvbXBsZXRlLAojICAgICAgICAgICBteV9wYXRoKCJEIiwiUGFydGlhbCIsIG5hbWUgPSAidG9wX3BvcnRzLmNzdiIpCiMgICAgICAgICAgICkKCm5vYWFfcG9ydHNfY29tcGxldGUKCmBgYAoKIyMjIyMjIDQuMS4xIFZpc3VhbGl6YXRpb24KCgpgYGB7cn0KCm5vYWFfcG9ydHNfY29tcGxldGUgJT4lIAogIGZpbHRlcih0cmVzaCA9PSAiNzV0aCIpICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludCgKICAgIGFlcygKICAgICAgeCA9IGxvbiwKICAgICAgeSA9IGxhdCwKICAgICAgc2hhcGUgPSBzcGVjaWVzX25hbWUsIAogICAgICBjb2xvciA9IHNwZWNpZXNfbmFtZQogICAgKSwKICAgIHNpemUgPSA1LAogICAgYWxwaGEgPSAwLjUKICApCgpgYGAKCgo8IS0tIFRoaXMgaXMgaG93IGFsbCB0aGUgc2hhcGVmaWxlcyBsb29rIGxpa2UgdG9nZXRoZXIgLS0+CgoKYGBge3IgYWxsX3NmLCBldmFsID0gVCwgZWNobyA9IFR9CgojIFZpc3VhbCBleHBsb3JhdGlvbiBvZiBhbGwgdG9nZXRoZXIgKG8uayEgKQpnZ3Bsb3QoKSArCiAgZ2VvbV9zZihkYXRhID0gZWV6X3NmLCBhZXMoKSkgKwogIGdlb21fc2YoZGF0YSA9IGxhbmRfc2YsIGFlcyhmaWxsID0gc3RhdGUpLCBhbHBoYSA9IDAuMykgKwogIGdlb21fc2YoZGF0YSA9IHN0YXRlX3NmLCBhZXMoY29sb3IgPSBzdGF0ZSksIGZpbGwgPSBOQSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHN1YnNldChub2FhX3BvcnRzX2NvbXBsZXRlLCB0cmVzaCA9PSAiNzV0aCIpLCBhZXMoeCA9IGxvbiwgeSA9IGxhdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gc3BlY2llc19uYW1lKSwgc2l6ZSA9IDMsIGFscGhhID0gMC43KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHN0YXRlX3BhbGxldCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHN0YXRlX3BhbGxldCkgKwogIHRoZW1lX2RhcmsoKSArCiAgY29vcmRfc2YoeWxpbSA9IGMoMzMsNDgpKQoKYGBgCgoKIyMjIENyZWF0ZSBiYXNlIHNoYXBlZmlsZSBmb3IgY29tcHV0YXRpb24KCkFzIGEgZmlyc3Qgc3RlcCB3ZSBuZWVkIHRvIGRpdmlkZSB0aGUgTkUgVVMgRUVaIGFtb25nIHRoZSBkaWZmZXJlbnQgc3RhdGVzLiBGb3IgdGhhdCwgd2UgZXhwYW5kZWQgYSBidWZmZXItcG9seWdvbiB0byB0aGUgMjAwIG5hdXRpY2FsIG1pbGVzIHRvIHRoZW4gZXN0aW1hdGUgdGhlIHBlcmNlbnRhZ2UgdGhhdCBlYWNoIGV4cGFuZGVkIHBvbHlnb24gb2NjdXBpZWQuIEZvciB0aGUgaW5pdGlhbCBidWZmZXIgcG9pbnQgd2UgdXNlZCB0d28gYXBwcm9hY2hlczsgc3RhdGUgd2F0ZXJzIGFuZCBVUyBwb3J0cy4gTm90ZSB0aGF0IGluIGFsbCBjYXNlcyB0aGVzZSBhcmVhcyBvdmVybGFwcGVkIGFuZCBwZXJjZW50YWdlcyBhY2NvdW50ZWQgZm9yIGl0LiBXZSBkaWQgdGhpcyBieSBmb2xsb3dpbmcgdGhlc2Ugc3RlcHM6CgotIDEuIEV4cGFuZCBzdGF0ZSB3YXRlcnMgLyBVUyBwb3J0cyB1c2luZyBhIGJ1ZmZlcgoKLSAyLiBHcmlkIHRoYXQgYnVmZmVyIG9uIGEgMC4zIHJlc29sdXRpb24KCi0gMy4gQ3JvcCB0aGUgYnVmZmVyIHRvIHRoZSBFRVoKCiMjIyMgMS4gRXhwYW5kIFNwYXRpYWwgcmVnaW9ucyAoYS5rLmEgIGJ1ZmZlcnMpCgojIyMjIyAxLjEgU3RhdGUgV2F0ZXJzCgpXZSBzZXQgYSBidWZmZXIgb2YgKjQxMDAwMCogbSAoNDEwIGttLCB+IDIyMSBubSkgdGhhdCBvdmVyc2hvb3RzIHRoZSBFRVogYSBiaXQsIGJ1dCBpcyBldmVudHVhbGx5IGNyb3BwZWQKCmBgYHtyIHN3X2J1ZmZlciwgZXZhbCA9IFQsIGVjaG8gPSBUfQoKIyBCdWZmZXIgc3RhdGUgd2F0ZXJzCnN0YXRlX2JmID0gc3RfYnVmZmVyKHN0YXRlX3NmLCA0KSAlPiUgCiAgc3RfdHJhbnNmb3JtKDQzMjYpICU+JSAjIHRvIG1hdGNoIHNoYXBlCiAgc3Rfc2V0X2Nycyg0MzI2KQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gIwojIFRlc3RpbmcgYW5kIHZpc3VhbGl6aW5nIHRoZSBidWZmZXIgCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICMKCnN0YXRlX2JmX3Bsb3QgPC0gZ2dwbG90KCkgKwogIGdlb21fc2YoZGF0YSA9IHN0YXRlX3NmLCBhZXMoY29sb3IgPSBzdGF0ZSksIGZpbGwgPSBOQSkgKwogIGdlb21fc2YoZGF0YSA9IGVlel9zZiwgYWVzKCksIGZpbGwgPSBOQSkgKwogIGdlb21fc2YoZGF0YSA9IHN0YXRlX2JmLCBhZXMoY29sb3IgPSBzdGF0ZSksIGZpbGwgPSBOQSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBzdGF0ZV9wYWxsZXQpKwogIHRoZW1lX2RhcmsoKQojICAgCgojIGdnc2F2ZSgiLi4vUmVzdWx0cy9QYXJ0aWFsL3N0YXRlX3dhdGVyc19idWZmZXIucG5nIixzdGF0ZV9iZl9wbG90KQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gIwoKc3RhdGVfYmZfcGxvdAoKYGBgCgojIyMjIyAxLjEgVVMuIFBvcnRzCgpXZSBzZXQgYSBidWZmZXIgb2YgKjUqIGRlZyAoNTEwIGttLCB+IDIyMSBubSkgdGhhdCBvdmVyc2hvb3RzIHRoZSBFRVogYSBiaXQsIGJ1dCBpcyBldmVudHVhbGx5IGNyb3BwZWQKCmBgYHtyIGZwX2J1ZmZlciwgZXZhbCA9IFQsIGVjaG8gPSBUfQoKCiNMb2FkIHRvcCBwb3J0IGRhdGEgCnBvcnRzX2RmIDwtIG15X3BhdGgoIkQiLCJQYXJ0aWFsIiwgInRvcF9wb3J0cy5jc3YiLCByZWFkID0gVCkgJT4lIAogIGZpbHRlcih0cmVzaCA9PSAiNzV0aCIpICU+JQogIGRpc3RpbmN0KHBvcnRfbmFtZSwgLmtlZXBfYWxsID0gVCkgIyBObyBuZWVkIGZvciBkdXBsaWNhdGlvbgoKcG9ydF9zZiA8LSBzdF9hc19zZihwb3J0c19kZiwKICAgICAgICAgICAgICAgICAgICBjb29yZHMgPWMoImxvbiIsImxhdCIpLAogICAgICAgICAgICAgICAgICAgIGNycyA9IDQzMjYpCgojIEJ1ZmZlciBzdGF0ZSB3YXRlcnMKcG9ydF9iZiA8LSBzdF9idWZmZXIocG9ydF9zZiwgNSkgJT4lICMgcG9ydAogIHN0X3RyYW5zZm9ybSg0MzI2KSAlPiUgIyB0byBtYXRjaCBzaGFwZQogIHN0X3NldF9jcnMoNDMyNikKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICMKIyBUZXN0aW5nIGFuZCB2aXN1YWxpemluZyB0aGUgYnVmZmVyIAojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAjCgpnZ3Bsb3QoKSArCiAgZ2VvbV9zZihkYXRhID0gZWV6X3NmLCBhZXMoKSxmaWxsID0gTkEpICsKICBnZW9tX3NmKGRhdGEgPSBwb3J0X2JmLCBhZXMoKSwgZmlsbCA9IE5BKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHN0YXRlX3BhbGxldCkrCiAgdGhlbWVfZGFyaygpCgpgYGAKCgojIyMjIDIuIEV4cGFuZCBncmlkIHdpdGhpbiBidWZmZXIKCkhlcmUgd2UgZXhwYW5kIGEgZ3JpZCB3aXRoaW4gdGhlIGJ1ZmZlciBzbyB3ZSBjYW4gZXN0aW1hdGUgdGhlIHByb3BvcnRpb24gb2YgZWFjaCBzdGF0ZS4KCipOb3RlOiogRGFyayBncmV5IHNoYWRlZCBhcmVhIGlzIHRoZSBncmlkIGFuZCBpcyB0aGUgc2FtZSBmb3IgYm90aCBhcHByb2FjaGVzCgpgYGB7ciBncmlkX2luZGV4aW5nLCBldmFsID0gVCwgZWNobyA9IFQsIG1lc3NhZ2UgPSBGLCB3YXJuaW5nID0gRn0KCiMgQ3JlYXRlIGdyaWQgb2YgdGhlIHJlZ2lvbgpiYm94IDwtIGMoc3RfYmJveChzdGF0ZV9iZikpCgojIEV4cGFuZCB0aGUgZ3JpZApuZV9ncmlkIDwtIGV4cGFuZC5ncmlkKAogICAgbG9uID0gc2VxKGZyb20gPSBiYm94WyJ4bWluIl0sIHRvID0gYmJveFsieG1heCJdLCBieSA9IDAuMyksCiAgICBsYXQgPSBzZXEoZnJvbSA9IGJib3hbInltaW4iXSwgdG8gPSBiYm94WyJ5bWF4Il0sIGJ5ID0gMC4zKQopICU+JSAKICByb3dpZF90b19jb2x1bW4oImluZGV4IikKCiMgLS0tLS0tLS0tLS0gIwojIFtURVNUXSBQbG90IGFsbCBsYXllcnMKIyAtLS0tLS0tLS0tLSAjCgojIExvb2tzIGdvb2QKc3RhdGVfc2YgJT4lCiAgc3RfdHJhbnNmb3JtKDQzMjYpICU+JSAjIHRvIG1hdGNoIHNoYXBlCiAgc3Rfc2V0X2Nycyg0MzI2KSAlPiUKICAjIHN0X3NpbXBsaWZ5KHByZXNlcnZlVG9wb2xvZ3kgPSBUUlVFLCBkVG9sZXJhbmNlID0gMTAwMDApICU+JQogIGdncGxvdCgpICsKICBnZW9tX3NmKGFlcyhjb2xvciA9IHN0YXRlKSkrCiAgIyBnZW9tX3NmKGRhdGEgPSBlZXpfc2YsIGFlcygpLGZpbGwgPU5BKSArCiAgIyBnZ3Bsb3QoKSsKICBnZW9tX3RpbGUoZGF0YSA9IG5lX2dyaWQsCiAgICAgICAgICAgIGFlcygKICAgICAgICAgICAgICB4ID0gbG9uLAogICAgICAgICAgICAgIHkgPSBsYXQKICAgICAgICAgICAgKSwKICAgICAgICAgICAgYWxwaGEgPSAwLjIKICApICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gc3RhdGVfcGFsbGV0KSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWVfZGFyaygpCgpgYGAKCiMjIyMjIDIuMSBDcmVhdGUgZ3JpZCBmb3IgaW50ZXJwb2xhdGlvbgoKYGBge3IgaW50ZXJfZ3JpZCwgZXZhbCA9IFQsIGVjaG8gPSBUfQoKIyBDcm9wIGdyaWQgdG8gRUV6CmludGVyX2dyaWRfc2YgPC0gc3RfYXNfc2YobmVfZ3JpZCwKICAgICAgICAgICAgIGNvb3JkcyA9IGMoImxvbiIsICJsYXQiKSwKICAgICAgICAgICAgIGNycyA9IDQzMjYpICU+JSAKICBzdF9pbnRlcnNlY3Rpb24oZWV6X3NmKQoKaW50ZXJfZ3JpZF9kZiA8LSBhcy5kYXRhLmZyYW1lKGludGVyX2dyaWRfc2YpICU+JSAKICBzZWxlY3QoaW5kZXgpICU+JSAKICBsZWZ0X2pvaW4obmVfZ3JpZCkKCiMgU2F2ZSBncmlkIGZvciBmdXR1cmUgYW5hbHlzaXMKIyB3cml0ZV9jc3YoaW50ZXJfZ3JpZF9kZiwgcGFzdGUwKG15X3BhdGgoIlIiLCAiUGFydGlhbCIpLCJpbnRlcl9ncmlkX2RmLmNzdiIpKQoKCmdncGxvdChpbnRlcl9ncmlkX3NmKSArCiAgZ2VvbV9zZigpCgoKYGBgCgoKIyMjIyMgMi4xIE1lcmdlIGdyaWQgYW5kIGJ1ZmZlcnMKCk9uY2Ugd2UgaGF2ZSBhIGdyaWRkZWQgYXJlYSwgd2UgY29udmVydGVkIHRoZSBncmlkIHRvIGEgYHNmYCBzbyB3ZSBjYW4gbWVyZ2UgaXQgd2l0aCB0aGUgYnVmZmVyZWQgc3RhdGVzIGFuZCBwb3J0cyBhbmQgZmluYWxseSBmaWx0ZXIgb3V0IGV2ZXJ5dGhpbmcgb3V0c2lkZSB0aGUgc3RhdGVzIHBvbHlnb24KCiMjIyMjIyAyLjEuMSBTdGF0ZSBXYXRlcnMKCmBgYHtyIGdyaWRfc3dfYnVmX21lcmdlLCBldmFsID0gVCwgZWNobyA9IFQsIG1lc3NhZ2UgPSBGLCB3YXJuaW5nID0gRiwgZmlnLndpZHRoID0gMTB9CgojIC0tLS0tLS0tLS0tLS0tLS0gIwojIENvbnZlcnQgZ3JpZCB0byBzZgojIC0tLS0tLS0tLS0tLS0tLS0gIwpncmlkX3N3X3NmIDwtIHN0X2FzX3NmKG5lX2dyaWQsCiAgICAgICAgICAgICBjb29yZHMgPSBjKCJsb24iLCAibGF0IiksCiAgICAgICAgICAgICBjcnMgPSA0MzI2KSAlPiUgCiAgc3Rfam9pbihzdGF0ZV9iZikgJT4lIAogIGZpbHRlcighaXMubmEoc3RhdGUpKQoKIyBDcmVhdGUgZGF0YSBmcmFtZSBmb3IgZnV0dXJlIGNvbXB1dGF0aW9ucwojIE5vdGUsIHdpbGwgYmUgdXNlZCBpbiBuZXh0IGNodW5rCmdyaWRfc3dfYmZfZHQgPC0gYXMuZGF0YS5mcmFtZShncmlkX3N3X3NmKSAlPiUKICAgIHNlbGVjdChpbmRleCxzdGF0ZSkKICAgICMgZ3JvdXBfYnkoc3RhdGUpICU+JSAKICAgICMgc3VtbWFyaXNlKGxlbmd0aChpbmRleCkpCgoKIyAtLS0tLS0tLS0tLS0tLS0tICMKIyBbVEVTVF0gCiMgVmlzdWFsaXphdGlvbiBvZiBncmlkCiMgLS0tLS0tLS0tLS0tLS0tLSAjCgpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZSgKICAjIE92ZXJhbGwgKG92ZXJsYXBwaW5nKSBwb3NpdGlvbgogIGdncGxvdChncmlkX3N3X3NmKSArCiAgICBnZW9tX3NmKGRhdGEgPSBzdGF0ZV9zZiwgYWVzKCksIGZpbGwgPSBOQSkgKwogICAgZ2VvbV9zZihhZXMoY29sb3IgPSBzdGF0ZSksIGFscGhhID0gMC4zKSArCiAgICBnZW9tX3NmKGRhdGEgPSBlZXpfc2YsIGFlcygpLGZpbGwgPU5BKSArIAogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHN0YXRlX3BhbGxldCkgKwogICAgdGhlbWVfZGFyaygpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICIiKSwKICAjIFNob3dpbmcgZWFjaCBzdGF0ZSBzZXBhcmF0bGV5CiAgZ2dwbG90KCkgKwogICAgZ2VvbV9zZihkYXRhID0gZ3JpZF9zd19zZiwgYWVzKGNvbG9yID0gc3RhdGUpLHNpemUgPSAwLjEsIGFscGhhID0gMC41KSArCiAgICBmYWNldF93cmFwKH5zdGF0ZSkgKwogICAgdGhlbWVfZGFyaygpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gc3RhdGVfcGFsbGV0KSwKICBucm93ID0gMSkgCgpgYGAKCiMjIyMjIyAyLjEuMSBGaXNoaW5nIFBvcnRzCgpgYGB7ciBncmlkX2ZwX2J1Zl9tZXJnZSwgZXZhbCA9IFQsIGVjaG8gPSBULCBtZXNzYWdlID0gRiwgd2FybmluZyA9IEYsIGZpZy53aWR0aCA9IDEwfQoKIyAtLS0tLS0tLS0tLS0tLS0tICMKIyBDb252ZXJ0IGdyaWQgdG8gc2YgCiMgLS0tLS0tLS0tLS0tLS0tLSAjCmdyaWRfZnBfc2YgPC0gc3RfYXNfc2YobmVfZ3JpZCwKICAgICAgICAgICAgIGNvb3JkcyA9IGMoImxvbiIsICJsYXQiKSwKICAgICAgICAgICAgIGNycyA9IDQzMjYpICU+JSAKICBzdF9qb2luKHBvcnRfYmYpICU+JSAjIGpvaW4gdG8gcG9ydCBzZgogIGZpbHRlcighaXMubmEocG9ydF9uYW1lKSkgJT4lCiAgZGlzdGluY3QoaW5kZXgscG9ydF9uYW1lLCAua2VlcF9hbGwgPSBUUlVFKSAjcmVtb3ZlcyBsaWtlIDQwMEsgb3ZlcmxhcHBpbmcgcm93cwoKIyBDcmVhdGUgZGF0YSBmcmFtZSBmb3IgZnV0dXJlIGNvbXB1dGF0aW9ucwojIE5vdGUsIHdpbGwgYmUgdXNlZCBpbiBuZXh0IGNodW5rCmdyaWRfZnBfYmZfZHQgPC0gYXMuZGF0YS5mcmFtZShncmlkX2ZwX3NmKSAlPiUKICAgIHNlbGVjdChpbmRleCxwb3J0X25hbWUsc3BlY2llc19uYW1lKQoKIyAtLS0tLS0tLS0tLS0tLS0tICMKIyBbVEVTVF0gCiMgVmlzdWFsaXphdGlvbiBvZiBncmlkCiMgLS0tLS0tLS0tLS0tLS0tLSAjCgpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZSgKICAjIE92ZXJhbGwgKG92ZXJsYXBwaW5nKSBwb3NpdGlvbgogIGdncGxvdChncmlkX2ZwX3NmKSArCiAgICBnZW9tX3NmKGRhdGEgPSBwb3J0X3NmLCBhZXMoKSwgZmlsbCA9IE5BKSArCiAgICBnZW9tX3NmKGFlcyhjb2xvciA9IHN0YXRlX3Bvc3RhbCksIGFscGhhID0gMC4zKSArCiAgICBnZW9tX3NmKGRhdGEgPSBlZXpfc2YsIGFlcygpLGZpbGwgPU5BKSArIAogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHN0YXRlX3BhbGxldCkgKwogICAgdGhlbWVfZGFyaygpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICIiKSwKICAjIFNob3dpbmcgZWFjaCBzdGF0ZSBzZXBhcmF0ZWx5CiAgZ2dwbG90KCkgKwogICAgZ2VvbV9zZihkYXRhID0gZ3JpZF9mcF9zZiwgYWVzKGNvbG9yID0gc3RhdGVfcG9zdGFsKSxzaXplID0gMC4xLCBhbHBoYSA9IDAuNSkgKwogICAgZmFjZXRfd3JhcCh+c3RhdGVfcG9zdGFsKSArCiAgICB0aGVtZV9kYXJrKCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBzdGF0ZV9wYWxsZXQpLAogIG5yb3cgPSAxKQoKYGBgCgojIyMjIDMuIENyb3AgYnVmZmVycyB0byBFRVoKCkZpbmFsbHksIHdlIGNyb3AgdGhlIGdyaWRlZCBidWZmZXJzIHRvIHdpdGhpbiB0aGUgRUVaIHRvIGNhcHR1cmUgdGhlIGFjdHVhbCB3YXRlciBzcGFjZS4KCipOb3RlOiogVGhpcyBzdGVwIHRha2VzIHF1aXRlIGEgd2hpbGUgYmVjYXVzZSBvZiB0aGUgc2l6ZSBvZiB0aGUgRUVaIHNoYXBlZmlsZS4gTm8sIHlvdSBjYW5ub3QgdXNlIGBzdF9zaW1wbGlmeSgpYCBoZXJlCgojIyMjIDMuMSBTdGF0ZSBXYXRlcnMKCmBgYHtyIGJ1ZmZfc3dfdG9fZWV6LCBldmFsID1ULCBlY2hvID0gVCwgbWVzc2FnZSA9IEYsIHdhcm5pbmcgPSBGfQoKIyBJIGRvbid0IGtub3cgaG93IHRvIHVuZG8gc3Rfc2ltcGxpZnkgc28gbmVlZCB0byByZS1sb2FkIHRoZSBzaGFwZWZpbGUKCmVlel9zZiA8LSBzdF9yZWFkKG15X3BhdGgoIkciLCBleHRyYV9wYXRoID0gIlNwYXRpYWwvU0FVL1NBVV9TaGFwZWZpbGUiLCBuYW1lID0gIlNBVUVFWl9KdWx5MjAxNS5zaHAiKSkgJT4lIAogIHJlbmFtZShlZXpfbmFtZSA9IE5hbWUpICU+JSAKICBzdF90cmFuc2Zvcm0oY3JzID0gNDMyNikgJT4lICMgNDMyNgogIGZpbHRlcihlZXpfbmFtZSA9PSAiVVNBIChFYXN0IENvYXN0KSIpIAoKIyBHZXQgdGhlIG92ZXJsYXBwaW5nIHNlZ21lbnRzIAojIE5PVEU6IFRha2VzIHNvbWUgZ29vb29vb2QgdGltZSAofjIwIG1pbikKU3lzLnRpbWUoKQpncmlkX2Vlel9zd19zZiA8LSBzdF9pbnRlcnNlY3Rpb24oZ3JpZF9zd19zZixlZXpfc2YpClN5cy50aW1lKCkKCiMgd3JpdGVfc2YoZ3JpZF9lZXpfc3dfc2YsIHBhc3RlMChteV9wYXRoKCJEIiwgIlNwYXRpYWwvZ3JpZF9lZXpfc3dfc2YiKSwiZ3JpZF9lZXpfc3dfc2Yuc2hwIikpCmdyaWRfZWV6X3N3X3NmIDwtIG15X3BhdGgoIkQiLCJTcGF0aWFsL2dyaWRfZWV6X3N3X3NmIiwgbmFtZSA9ICJncmlkX2Vlel9zd19kZi5jc3YiLHJlYWQgPSBUKQoKIyBHZXQgZmluYWwgZGYgd2l0aCBpbmRleApncmlkX2Vlel9zd19kZiA8LSBhcy5kYXRhLmZyYW1lKGdyaWRfZWV6X3N3X3NmKSAlPiUKICBzZWxlY3Qoc3RhdGUsYWJyZXYsaW5kZXgpICU+JQogIGxlZnRfam9pbihuZV9ncmlkLAogICAgICAgICAgICBieSA9ICJpbmRleCIpCgojIHdyaXRlX2NzdihncmlkX2Vlel9zd19kZiwgcGFzdGUwKG15X3BhdGgoIkQiLCAiU3BhdGlhbC9ncmlkX2Vlel9zd19zZiIsImdyaWRfZWV6X3N3X2RmLmNzdiIpKSkKCiMgUGxvdCB0byBtYWtlIHN1cmUgbWFrZXMgc2Vuc2UKCmVlel9zZiA8LSBlZXpfc2YgJT4lIAogIHN0X3NpbXBsaWZ5KHByZXNlcnZlVG9wb2xvZ3kgPSBUUlVFLCBkVG9sZXJhbmNlID0gMC4xKSAjMC4xIGZvciBwYXBlcgoKZ3JpZF9lZXpfc3dfZGYgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fc2YoYWVzKGNvbG9yID0gc3RhdGUpLCBhbHBoYSA9IDAuMykgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBzdGF0ZV9wYWxsZXQpICsKICBnZW9tX3NmKGRhdGEgPSBlZXpfc2YsYWVzKCksIGZpbGwgPSBOQSkgKwogIHRoZW1lX2RhcmsoKQoKYGBgCgoKIyMjIyAzLjIgRmlzaGluZyBQb3J0cwoKYGBge3IgYnVmZl9mcF90b19lZXosIGV2YWwgPVQsIGVjaG8gPSBULCBtZXNzYWdlID0gRiwgd2FybmluZyA9IEZ9CgpzdGF0ZV9uYW1lcyA8LSBncmlkX2Vlel9zd19kZiAlPiUgCiAgc2VsZWN0KHN0YXRlLGFicmV2KSAlPiUgCiAgZGlzdGluY3QoLmtlZXBfYWxsID0gVCkKCiMgR2V0IHRoZSBvdmVybGFwcGluZyBzZWdtZW50cyAKIyBOT1RFOiBUYWtlcyBzb21lIGdvb29vb29kIHRpbWUgKH4yMCBtaW4pClN5cy50aW1lKCkKZ3JpZF9lZXpfc2ZfZnAgPC0gc3RfaW50ZXJzZWN0aW9uKGdyaWRfZnBfc2YsZWV6X3NmKQpTeXMudGltZSgpCgp3cml0ZV9zZihncmlkX2Vlel9zZl9mcCwgbXlfcGF0aCgiUiIsICJQYXJ0aWFsIixuYW1lPSJncmlkX2Vlel9mcC5zaHAiKSkKCiMgR2V0IGZpbmFsIGRmIHdpdGggaW5kZXgKZ3JpZF9lZXpfZnBfZGYgPC0gYXMuZGF0YS5mcmFtZShncmlkX2Vlel9zZl9mcCkgJT4lCiAgc2VsZWN0KGluZGV4LHBvcnRfbmFtZSxhYnJldj1zdGF0ZV9wb3N0YWwsc3BwPXNwZWNpZXNfbmFtZSkgJT4lIAogIGxlZnRfam9pbihuZV9ncmlkLAogICAgICAgICAgICBieSA9ICJpbmRleCIpCgp3cml0ZV9jc3YoZ3JpZF9lZXpfZnBfZGYsIG15X3BhdGgoIlIiLCAiUGFydGlhbC9ncmlkX2ZwIixuYW1lID0gImdyaWRfZWV6X2ZwX2RmLmNzdiIpKQoKIyBQbG90IHRvIG1ha2Ugc3VyZSBtYWtlcyBzZW5zZQpncmlkX2Vlel9zZl9mcCAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9zZihhZXMoY29sb3IgPSBzdGF0ZV9wb3N0YWwpLCBhbHBoYSA9IDAuMykgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBzdGF0ZV9wYWxsZXQpICsKICBnZW9tX3NmKGRhdGEgPSBlZXpfc2YsYWVzKCksIGZpbGwgPSBOQSkgKwogIHRoZW1lX2RhcmsoKQoKYGBgCgojIyMjIDMuMyBEaWZmZXJlbmNlcyBhdCBjcm9wZWQgbGV2ZWwKCkJ5IGxvb2tpbmcgYXQgdGhlIHBsb3RzIHdlIGRvIG5vdCBzZWUgdGhhdCB0aGUgbnVtYmVyIG9mIGdyaWQgY2VsbHMgdGhhdCBlYWNoIHN0YXRlIGhhcyBpcyBzbGlnaHRseSBkaWZmZXJlbnQgZGVwZW5kaW5nIG9uIHRoZSBhcHByb2FjaC4gVGhpcyBjb21lcyB0byBsaWdodCB3aGVuIHdlIGNvdW50IHRoZSBudW1iZXIgb2YgZ3JpZGNlbGxzIHRoYXQgZWFjaCBzdGF0ZSBnZXRzIGluIGVhY2ggYXBwcm9hY2guIFdlIHNlZSB0aGF0IHRoZSBzdGF0ZSB3YXRlcnMgb25lIGlzIHN1YnN0YW50aWFsbHkgaGlnaGVyLgoKV2UgY2FuIHZpc3VhbGl6ZSB0aGUgZGlmZmVyZW5jZSBvZiB0aGUgY3JvcHBlZCBhcmVhIGZvciBlYWNoIHN0YXRlIG5leHQuIEFnYWluLCB0aGUgZmlzaGluZyBwb3J0IGFwcHJvYWNoIHJlc3VsdHMgaW4gbGVzcyBhcmVhIGZvciBhbGwgc3RhdGVzLCBidXQgc3VjaCBhcmVhIGlzIG5vdCBwcm9wb3J0aW9uYWwgYW1vbmcgc3RhdGVzLiBGb3IgZXhhbXBsZSwgRGVsYXdhcmUgbG9vc2VzIHJvdWdobHkgMzUlIG9mIGZpc2hpbmcgZ3JvdW5kcyB3aXRoIHRoaXMgYXBwcm9hY2gKCmBgYHtyIHN0YXRlX2JmX2RpZmZfbnRibCwgZXZhbCA9IFQsIGVjaG8gPSBUfQoKZ3JpZF9lZXpfc3dfZGYgJT4lIAogIG11dGF0ZShhcHByb2FjaCA9ICJzdGF0ZV93YXRlcnMiKSAlPiUgCiAgYmluZF9yb3dzKGdyaWRfZWV6X2ZwX2RmKSAlPiUKICBtdXRhdGUoYXBwcm9hY2ggPSBpZmVsc2UoaXMubmEoYXBwcm9hY2gpLCJmaXNoaW5nX3BvcnQiLGFwcHJvYWNoKSkgJT4lIAogIGdyb3VwX2J5KHN0YXRlLGFwcHJvYWNoKSAlPiUgCiAgc3VtbWFyaXNlKG5fZ3JpZCA9IG4oKSkgJT4lIAogIHNwcmVhZChhcHByb2FjaCxuX2dyaWQpICU+JSAKICBtdXRhdGUoZGlmZmVyZW5jZSA9c3RhdGVfd2F0ZXJzLWZpc2hpbmdfcG9ydCwKICAgICAgICAgcGVyY2VudGFnZV9zdyA9IHJvdW5kKChkaWZmZXJlbmNlL3N0YXRlX3dhdGVycykqMTAwKQogICAgICAgICApCgpgYGAKCkFuZCBoZXJlIGlzIHRoZSBtYXAgdmlzdWFsaXphdGlvbiBvZiB0aGUgY3JvcHBlZCBkaWZmZXJlbmNlCgpgYGB7ciBzdGF0ZV9iZl9kaWZmX21hcCwgZXZhbCA9IFQsIGVjaG8gPSBUfQoKZ3JpZF9lZXpfc3dfZGYgJT4lIAogIG11dGF0ZShhcHByb2FjaCA9ICJzdGF0ZV93YXRlcnMiKSAlPiUgCiAgYmluZF9yb3dzKGdyaWRfZWV6X2ZwX2RmKSAlPiUKICBtdXRhdGUoYXBwcm9hY2ggPSBpZmVsc2UoaXMubmEoYXBwcm9hY2gpLCJmaXNoaW5nX3BvcnQiLGFwcHJvYWNoKSkgJT4lIAogIGdncGxvdCgpICsKICBnZW9tX3RpbGUoCiAgICBhZXMoCiAgICAgIHggPSBsb24sCiAgICAgIHkgPSBsYXQsCiAgICAgIGZpbGwgPSBhcHByb2FjaAogICAgKSwKICAgIGFscGhhID0gMC41CiAgKSArCiAgZmFjZXRfd3JhcCh+c3RhdGUpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIpICsKICB0aGVtZV9kYXJrKCkKCmBgYAoKCiMjIyBJbnRlcnBvbGF0aW9uIHJ1dGluZQoKSW4gdGhpcyBzdGVwIHdlIFtpbnRlcnBvbGF0ZV0oaHR0cHM6Ly9zd2lsa2UtZ2Vvc2NpZW5jZS5uZXQvcG9zdC9zcGF0aWFsX2ludGVycG9sYXRpb24vKSB0aGUgc3VydmV5IGRhdGEgd2l0aGluIHRoZSBwcmV2aW91c2x5IGNyZWF0ZWQgZ3JpZCBmb2xsb3dpbmcgYSBUcmlhbmd1bGFyIElycmVndWxhciBTdXJmYWNlIG1ldGhvZC4KCiMjIyMgRnVuY3Rpb25zIG5lZWRlZAoKV2UgbmVlZCB0byBjcmVhdGUgYSBjb3VwbGUgb2YgZnVuY3Rpb25zIHRvIHJ1biB0aGUgd2hvbGUgcHJvY2VzcwoKIyMjIyMgSW50ZXJwb2xhdGlvbiBtYWluIGZ4ICh0aXMpLgoKVGhpcyBpcyB0aGUgbWFpbiBmdW5jdGlvbiB1c2VkIHRvIGludGVycG9sYXRlIHRoZSBkYXRhIHBlciB5ZWFyLiBJdCBmb2xsb3dzIGEgVHJpYW5ndWxhciBJcnJlZ3VsYXIgU3VyZmFjZSBtZXRob2QgdXNpbmcgdGhlIGBpbnRlcnA6OmludGVycCgpYCBmdW5jdGlvbi4gSWYgeW91IHdhbnQgdG8gc2VlIHRoZSBmdW5jdGlvbiBjbGljIG9uIGBjb2RlYAoKYGBge3IgaW50ZXJwb2xfZnVuY3Rpb24sIGV2YWwgPSBULCBlY2hvID0gVH0KCnRpcyA8LSBmdW5jdGlvbihpbnB1dF9kYXRhLCBncmlkLCB5ciwgdGF4YSwgcmVnKXsKICAKICAjIC0tLS0tLS0tLS0tLS0tLSAjCiAgIyBUZXN0aW5nCiAgIyBwcmludChwYXN0ZSh5cikpCiAgIyB5ciA9IDE5NzYKICAjIC0tLS0tLS0tLS0tLS0tLSAjCiAgCiAgIyBGaWx0ZXIgZGF0YQogIGRhdGEgPC0gaW5wdXRfZGF0YSAlPiUgCiAgICBmaWx0ZXIoeWVhciA9PSB5ciwKICAgICAgICAgICBzcHAgPT0gdGF4YSwKICAgICAgICAgICByZWdpb24gPT0gcmVnCiAgICApICU+JSAKICAgICMgQXZlcmFnZSBkdXBsaWNhdGVkIGhhdWxzIGluIHRoZSBzYW1lIHNwb3QKICAgIGdyb3VwX2J5KHJlZ2lvbix5ZWFyLHNwcCxsYXQsbG9uKSAlPiUKICAgIHN1bW1hcmlzZV9hdCh2YXJzKHd0Y3B1ZSksCiAgICAgICAgICAgICAgICAgbWVhbixuYS5ybSA9IFQpCiAgICAKICAjIE9ubHkgaW50ZXJwb2xhdGUgY2FzZXMgd2hlcmUgdGhlcmUgaXMgbW9yZSB0aGFuIDMgcm93cwogICMgTWFya2VkIGJ5IHRoZSBmdW5jdGlvbiAKICAgIGlmKG5yb3coZGF0YSkgPD0gMyl7CiAgICAgIGZpdF90aW4gPC0gdGliYmxlKCkKICAgIH1lbHNlewogICAgICAKICAgICAgIyBUcmlhbmd1bGFyIElycmVndWxhciBTdXJmYWNlCiAgICAgIGZpdF90aW4gPC0gaW50ZXJwOjppbnRlcnAoICMgdXNpbmcge2ludGVycH0KICAgICAgICB4ID0gZGF0YSRsb24sICAgICAgICAgICAjIHRoZSBmdW5jdGlvbiBhY3R1YWxseSBhY2NlcHRzIGNvb3JkaW5hdGUgdmVjdG9ycwogICAgICAgIHkgPSBkYXRhJGxhdCwKICAgICAgICB6ID0gZGF0YSR3dGNwdWUsCiAgICAgICAgeG8gPSBncmlkJGxvbiwgICAgICMgaGVyZSB3ZSBhbHJlYWR5IGRlZmluZSB0aGUgdGFyZ2V0IGdyaWQKICAgICAgICB5byA9IGdyaWQkbGF0LAogICAgICAgIG91dHB1dCA9ICJwb2ludHMiCiAgICAgICkgJT4lIAogICAgICAgIGJpbmRfY29scygpICU+JSAKICAgICAgICBiaW5kX2NvbHMoZ3JpZCkgJT4lCiAgICAgICAgbXV0YXRlKHllYXIgPSB5ciwKICAgICAgICAgICAgICAgcmVnaW9uID0gcmVnLAogICAgICAgICAgICAgICBzcHAgPSB0YXhhKSAlPiUgCiAgICAgICAgc2VsZWN0KGluZGV4LCAKICAgICAgICAgICAgICAgIyBzdGF0ZSwKICAgICAgICAgICAgICAgeWVhciwgcmVnaW9uLCBzcHAsIGxvbj14LCBsYXQ9eSwgdmFsdWUgPSB6KQogICAgICAKICAgIH0KICAgCiAgICByZXR1cm4oZml0X3RpbikKfQoKIyBUZXN0IG1lCiMgTmVlZHMgdmFyaWFibGVzIGluIENvbnRyb2wgcGFuZWwKIyBUZXN0IG5vIGRhdGE6ICJBbG9zYSBhZXN0aXZhbGlzIiwgcmVnID0gIk5vcnRoZWFzdCBVUyBGYWxsIiwgeXIgPSAxOTc0IAojIHRpcyhpbnB1dF9kYXRhID0gb2NlYW5fZGF0YSwgZ3JpZCA9IGdyaWRfZWV6X2RmLCB0YXhhID0gIklsbGV4IGlsbGVjZWJyb3N1cyIsIHJlZyA9ICJOb3J0aGVhc3QgVVMgRmFsbCIsIHlyID0gMTk3MykKCgoKIyBsYXBwbHkoeWVhcnMsdGlzLGlucHV0X2RhdGEgPSBvY2Vhbl9kYXRhLCBncmlkID0gZ3JpZF9lZXpfZGYsIHRheGEgPSAiSWxsZXggaWxsZWNlYnJvc3VzIiwgcmVnID0gcmVnaW9uc1syXSkKCmBgYAoKIyMjIyMgUnVuIGZ1bmN0aW9uCgpUaGlzIGlzIGEgc3ViLWZ1bmN0aW9uIHRoYXQgcnVucyB0aGUgYHRpcygpYCBmdW5jdGlvbiBieSB0YXhhIGFuZCByZWdpb24uIEl0IHNhdmVzIHRoZSBvdXRwdXQgYXMgYSAuY3N2IGZpbGUgZm9yIGVhY2ggc3BlY2llcy4gCgpgYGB7ciBpbnRlcnBvbF9ydW5fZnVuLCBldmFsID0gVCwgZWNobyA9IFR9CgoKcnVuX3RpcyA8LSBmdW5jdGlvbihpbnB1dF9kYXRhLCBncmlkLCB5ZWFycywgdGF4YSwgcmVnKXsKICAKICAKICAjIFJ1biB0aXMgZm9yIHNwZWNpZXMgYW5kIHN1cnZleXMKICBmb3IociBpbiAxOjIpewogICAgCiAgICBwYXJ0aWFsX2RmIDwtIGJpbmRfcm93cygKICAgICAgbGFwcGx5KHllYXJzLHRpcyxpbnB1dF9kYXRhID0gaW5wdXRfZGF0YSwgZ3JpZCA9IGdyaWQsIHRheGEgPSB0YXhhLCByZWcgPSByZWdbcl0pCiAgICApCiAgICAKICAgIGlmKHIgPT0gMSl7CiAgICAgIGhpc3RvcmljX3RpZiA8LSBwYXJ0aWFsX2RmCiAgICB9ZWxzZXsKICAgICAgaGlzdG9yaWNfdGlmIDwtIGJpbmRfcm93cyhoaXN0b3JpY190aWYscGFydGlhbF9kZikKICAgIH0KICAgIAogIH0KICAKICAjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICMKICAjIFNhdmUgZGF0YXNldCBwZXIgc3BlY2llcwogICMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gIwogIAogICMgU2V0IGZpbGUgbmFtZQogIG5hbWUgPC0gcGFzdGUwKCJ0aWZfIixzdHJfcmVwbGFjZSh0YXhhLCIgIiwiXyIpLCIuY3N2IikKICAKICBjb21wbGVtZW50IDwtIHBhc3RlMCgiUGFydGlhbC9JbnRlcnBvbGF0aW9uLyIpCiAgCiAgIyBTZXQgcGF0aCBuYW1lCiAgc2F2ZV9wYXRoIDwtIG15X3BhdGgoIlIiLGNvbXBsZW1lbnQpCiAgCiAgIyBTZXQgY29tcGxldGUgcGF0aAogIHNhdmVfbmFtZSA8LSBwYXN0ZTAoc2F2ZV9wYXRoLG5hbWUpCiAgCiAgIyBDcmVhdGUgZm9sZGVyIGlmIGl0IGRvZXMgbm90IGV4aXN0CiAgaWYoZmlsZS5leGlzdHMoc2F2ZV9wYXRoKSA9PSBGKXsKICAgIGRpci5jcmVhdGUoc2F2ZV9wYXRoKQogIH0KICAKICAjICBTYXZlIGZpbGUKICB3cml0ZV9jc3YoaGlzdG9yaWNfdGlmLHNhdmVfbmFtZSkKICAKICByZXR1cm5fbXNnIDwtIHBhc3RlKCJJbnRlcnBvbGF0aW9uIGRvbmUgZm9yIiwgdGF4YSkKICAKICByZXR1cm4ocmV0dXJuX21zZykKICAKICAKfQoKIyBUZXN0IG1lCiAgICAjIHJ1bl90aXMoaW5wdXRfZGF0YSA9IG9jZWFuX2RhdGEsIGdyaWQgPSBncmlkX2Vlel9mcF9kZiwgdGF4YSA9ICJDZW50cm9wcmlzdGlzIHN0cmlhdGEiLCB5ZWFycyA9IHNlcSgxOTcwLDE5ODApLCByZWcgPSByZWdpb25zLCBtZXRob2QgPSAidGVzdGEiKQoKYGBgCgoKIyMjIyBTdXJ2ZXkgZGF0YQoKVGhlIGludGVycG9sYXRpb24gd2FzIGRvbmUgd2l0aCBOT0FBIE5vcnRoZWFzdCBGaXNoZXJpZXMgU2NpZW5jZSBDZW50ZXIgU3ByaW5nIGFuZCBGYWxsIEJvdHRvbSBUcmF3bCBTdXJ2ZXlzIFtkYXRhXShodHRwczovL3d3dy5maXNoZXJpZXMubm9hYS5nb3YvcmVnaW9uL25ldy1lbmdsYW5kLW1pZC1hdGxhbnRpYyNzY2llbmNlKSBwcm92aWRlZCBieSBbT2NlYW4gYWRhcHRdKGh0dHBzOi8vb2NlYW5hZGFwdC5ydXRnZXJzLmVkdS8pLiBEYXRhIHdhcyBhY2Nlc3NlZCB0cm91Z2ggdGhlIFtHaXRodWJdKGh0dHBzOi8vZ2l0aHViLmNvbS9waW5za3lsYWIvT2NlYW5BZGFwdCkuCgoqSW4gcHJpbWFyeSBwdWJsaWNhdGlvbnMgdXNpbmcgZGF0YSBmcm9tIHRoZSBkYXRhYmFzZSwgcGxlYXNlIGNpdGUgUGluc2t5IGV0IGFsLiAyMDEzLiBNYXJpbmUgdGF4YSB0cmFjayBsb2NhbCBjbGltYXRlIHZlbG9jaXRpZXMuIFNjaWVuY2UgMzQxOiAxMjM5LTEyNDIgZG9pOiAxMC4xMTI2L3NjaWVuY2UuMTIzOTM1MiwgYXMgd2VsbCBhcyB0aGUgb3JpZ2luYWwgZGF0YSBzb3VyY2VzLioKCi0gVXNpbmcgb25seSB0aGUgTm9ydGhlYXN0IFVTIEZhbGwgYW5kIFNwcmluZyBib3R0b20gdHJhd2wgc3VydmV5IGRhdGEgZm9yIG5vdwoKIyMjIyMgU3BsaXR0aW5nIHVwIGRhdGEKCi0gTm8gcGFydCBvbiBzcGF0aWFsIGFuYWx5c2lzLiBDYW4gYmUgaWdub3JlZC4gCgpUaGlzIGlzIGp1c3QgYSBzdWItc3RlcCB0byBzcGxpdCB1cCB0aGUgZGF0YSBpbnRvIHNpbmdsZSBzcGVjaWVzIGZpbGVzLiBUaGlzIG1ha2VzIHRoZSBhcHAgZmFzdGVyIGFzIGl0IG9ubHkgbmVlZHMgdG8gbG9hZCBzcGVjaWVzIHNwZWNpZmljIGRhdGEsIHJhdGhlciB0aGFuIGFsbCB0aGUgZGF0YSBhdCBkZSBiZWdpbm5pbmcuIAoKYGBge3IgZGF0X2V4cGxvZGVkLCBldmFsID0gRiwgZWNobyA9IEYsIGZpZy53aWR0aCA9IDl9CgpvY2Vhbl9kYXRhIDwtIHJlYWRSRFMoIi9Wb2x1bWVzL0VudGVycHJpc2UvRGF0YS9waW5za3lsYWItT2NlYW5BZGFwdC05NjZhZGYwL2RhdGFfY2xlYW4vZGF0X2V4cGxvZGVkLnJkcyIpICMlPiUgCiAgIyBmaWx0ZXIoc3BwID09ICJDZW50cm9wcmlzdGlzIHN0cmlhdGEiLAogICAgICAgIyByZWdpb24gJWluJSBjKCJOb3J0aGVhc3QgVVMgRmFsbCIgLCAiTm9ydGhlYXN0IFVTIFNwcmluZyIpKSAjTm8gbW9yZSBzZWFzb25zCgoKc3BwX2RhdGEgPC0gZnVuY3Rpb24oc3BwKXsKICAKICBuYW1lX3NhdmUgPC0gcGFzdGUwKG15X3BhdGgoIkQiLCJTcHAvT2JzZXJ2YXRpb24iKSwib2JzXyIsc3RyX3JlcGxhY2Uoc3BwWzFdLCAiICIsICJfIiksIi5jc3YiKQoKb2NlYW5fZGF0YSAlPiUgCiAgZmlsdGVyKHNwcCA9PSBzcHAsCiAgICAgICByZWdpb24gJWluJSBjKCJOb3J0aGVhc3QgVVMgRmFsbCIgLCAiTm9ydGhlYXN0IFVTIFNwcmluZyIpCiAgICAgICApICU+JSAKICB3cml0ZV9jc3YoLiwgbmFtZV9zYXZlKQogIAp9CgpzcHBfbGlzdCA8LSBvY2Vhbl9kYXRhICU+JSAKICBmaWx0ZXIocmVnaW9uICVpbiUgcmVnaW9ucywKICAgICAgICAgc3BwICE9ICJOQSIpICU+JSAKICBwdWxsKHNwcCkgJT4lIAogIHVuaXF1ZSgpCiAgCgpsYXBwbHkoc3BwX2xpc3QsIHNwcF9kYXRhKQoKCnN1YnNldF9kYXRhIDwtIG9jZWFuX2RhdGEgJT4lIAogIGZpbHRlcihzcHAgPT0gIkNlbnRyb3ByaXN0aXMgc3RyaWF0YSIsCiAgICAgICByZWdpb24gJWluJSBjKCJOb3J0aGVhc3QgVVMgRmFsbCIgLCAiTm9ydGhlYXN0IFVTIFNwcmluZyIpCiAgICAgICApCgpnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gc3Vic2V0KHN1YnNldF9kYXRhLCB3dGNwdWUgPSAwLjApLAogICAgICAgICAgICAgYWVzKAogICAgICAgICAgICAgICB4ID0gbG9uLAogICAgICAgICAgICAgICB5ID0gbGF0CiAgICAgICAgICAgICApLAogICAgICAgICAgICAgY29sb3IgPSAiZ3JleTk1IgogICkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHN1YnNldChzdWJzZXRfZGF0YSwgd3RjcHVlID4gMCksCiAgICAgICAgICAgICBhZXMoCiAgICAgICAgICAgICAgIHggPSBsb24sCiAgICAgICAgICAgICAgIHkgPSBsYXQsCiAgICAgICAgICAgICAgIGNvbG9yID0gbG9nMTAod3RjcHVlKQogICAgICAgICAgICAgKSwKICAgICAgICAgICAgIHNpemUgPSAxCiAgKSArCiAgc2NhbGVfY29sb3JfZGlzdGlsbGVyKHBhbGV0dGUgPSAiU3BlY3RyYWwiLCAKICAgICAgICAgICAgICAgICAgICAgICAgZ3VpZGVfbGVnZW5kKHRpdGxlID0gIldDUFVFIHBlciBIYXVsIChsb2cxMCkiKSkgKyAKICBjb29yZF9zZih4bGltID0gYygtNzYsIC02NSkseWxpbSA9IGMoMzUsIDQ1KSkgKwogIE15RnVuY3Rpb25zOjpteV9nZ3RoZW1lX20oKSArCiAgZmFjZXRfd3JhcCh+cmVnaW9uKQoKYGBgCgojIyMjIENvbnRyb2wgUGFubmVsCgpUaGlzIGlzIHdoZXJlIHdlIGxvYWQgdGhlIHJlcXVpcmVkIGRhdGEgYW5kIHByZXBhcmUgdG8gcnVuIHRoZSBpbnRlcnBvbGF0aW9uIGZ1bmN0aW9uLiBOb3RlIHRoYXQgc29tZSBvZiB0aGUgZGF0YSBoZXJlIGhhcyBiZWVuIHByZXZpb3VzbHkgY3JlYXRlZCAKCmBgYHtyIGNvbnRyb19wYW5uZWwsIGV2YWwgPSBULCBlY2hvID0gVH0KCiMgTG9hZCBncmlkIGRmCiMgRm9yIGZpc2hpbmcgcG9ydHMKaW50ZXJfZ3JpZCA8LSBteV9wYXRoKCJEIiwiU3BhdGlhbCIsImludGVyX2dyaWRfZGYuY3N2IiwgcmVhZCA9IFQpCgojIFJ1biBpbnRlcnBvbGF0aW9uIGZvciBhbGwgeWVhcnMKeWVhcnMgPC0gc2VxKDE5NzMsMjAxOSwxKQoKIyByZWdpb25zCnJlZ2lvbnMgPC0gYygiTm9ydGhlYXN0IFVTIEZhbGwiICwgIk5vcnRoZWFzdCBVUyBTcHJpbmciKQoKIyBzcGVjaWVzIGxpc3QKc3BwIDwtIG9jZWFuX2RhdGEgJT4lIAogIGZpbHRlcihyZWdpb24gJWluJSByZWdpb25zLAogICAgICAgICBzcHAgIT0gIk5BIikgJT4lIAogIHB1bGwoc3BwKSAlPiUgCiAgdW5pcXVlKCkKCgojIERvdWJsZSBjaGVjayBydW5zCgpzcHBfcnVucyA8LSB0aWJibGUodGF4YSA9IChsaXN0LmZpbGVzKG15X3BhdGgoIlIiLCJQYXJ0aWFsL0ludGVycG9sYXRpb24vZnAiKSkpKSAlPiUKICBtdXRhdGUoCiAgICB0YXhhID0gc3RyX3JlbW92ZSh0YXhhLCAidGlmXyIpLAogICAgdGF4YSA9IHN0cl9yZW1vdmUodGF4YSwgIi5jc3YiKSwKICAgIHRheGEgPSBzdHJfcmVwbGFjZSh0YXhhLCAiXyIsICIgIikKICApIAoKIyBNaXNzaW5nIHJ1bnMKc3BwIDwtIHRpYmJsZSh0YXhhPXNwcCkgJT4lIAogIGFudGlfam9pbihzcHBfcnVucykgJT4lIAogIHB1bGwodGF4YSkKCgpgYGAKCiMjIyMgUnVuIHJvdXRpbmUKCkhlcmUgd2UganVzdCBydW4gdGhlIHJvdXRpbmUgZm9yIGVhY2ggb2YgdGhlIHNwZWNpZXMgcHJlc2VudCBpbiB0aGUgTm9ydGhlYXN0IFVTIEZhbGwgYW5kIFNwcmluZyBzdXJ2ZXlzIGJldHdlZW4gMTk3MyBhbmQgMjAxOS4gCgotIE5vdGUgdGhlcmUgYXJlIDQzIGlkZW50aWZpZWQgdGF4YQotIFNvbWUgdGF4YSBkbyBub3QgaGF2ZSBwcmVzZW5jZSBkYXRhIGluIHNvbWUgeWVhcnMKCmBgYHtyIHJ1bl9yb3V0aW5lLCBldmFsID0gVCwgZWNobyA9IFR9CgojICMgc2luZ2xlIHNwZWNpZXMgcnVuCnJ1bl90aXMoaW5wdXRfZGF0YSA9IG9jZWFuX2RhdGEsCiAgICAgICAgZ3JpZCA9IGdyaWRfZWV6X2ZwX2RmLAogICAgICAgIHllYXJzID0geWVhcnMsCiAgICAgICAgcmVnID0gcmVnaW9ucywKICAgICAgICB0YXhhID0gIlN0ZW5vdG9tdXMgY2hyeXNvcHMiLAogICAgICAgIG1ldGhvZCA9ICJmcCIKKQoKCiMgUnVuIHRoZW0gYWxsIGluIHBhcmFsbGVsCmxhcHBseShTcGVjaWVzLAogICAgICAgcnVuX3RpcywgCiAgICAgICBpbnB1dF9kYXRhID0gb2NlYW5fZGF0YSwKICAgICAgIGdyaWQgPSBpbnRlcl9ncmlkLAogICAgICAgeWVhcnMgPSB5ZWFycywKICAgICAgIHJlZyA9IHJlZ2lvbnMKKQoKCmBgYAoKIyBSZXN1bHRzCgpSZXN1bHRzIGFyZSBub3cgZm9yIGVpZ2h0IHNwZWNpZXMgbWFuYWdlZCB1bmRlciBNaWQtQXRsYW50aWMgQ291bmNpbCBNYW5hZ2VtZW50IFBsYW5zIGFjY29yZGluZyB0byBbTk9BQV0oaHR0cHM6Ly93d3cuZmlzaGVyaWVzLm5vYWEuZ292L25ldy1lbmdsYW5kLW1pZC1hdGxhbnRpYy9jb21tZXJjaWFsLWZpc2hpbmcvbmV3LWVuZ2xhbmQtbWlkLWF0bGFudGljLWZpc2hlcnktbWFuYWdlbWVudC1wbGFucykuCgoKU3RhdGUgYWxsb2NhdGlvbnMgb2YgdGhlIGNvbW1lcmNpYWwgYmxhY2sgc2VhIGJhc3MgY29hc3R3aWRlIHF1b3RhIHdlcmUgb3JpZ2luYWxseSBpbXBsZW1lbnRlZCBpbiAyMDAzIGFzIHBhcnQgb2YgQW1lbmRtZW50IDEzLCBsb29zZWx5IGJhc2VkIG9uIGhpc3RvcmljYWwgbGFuZGluZ3MgZnJvbSAxOTgwLSAyMDAxLiAKCgoqU2NvbWJlciBzY29tYnJ1cyosICpQZXByaWx1cyB0cmlhY2FudGh1cyogKGJ1dHRlcmZpc2gpLCAqSWxsZXggaWxsZWNlYnJvc3VzKiAoc2hvcnRmaW4gc3F1aWQpLCAqUGFyYWxpY2h0aHlzIGRlbnRhdHVzKiAoc3VtbWVyIGZsb3VuZGVyKSwgKlN0ZW5vdG9tdXMgY2hyeXNvcHMqIChTY29vcCksICpDZW50cm9wcmlzdGlzIHN0cmlhdGEqIChibGFjayBzZWEgYmFzcyksICpQb21hdG9tdXMgc2FsdGF0cml4KiAoQmx1ZWZpc2gpLCAqTG9waG9sYXRpbHVzIGNoYW1hZWxlb250aWNlcHMqIChHb2xkZW4gdGlsZWZpc2gpLCAqQ2F1bG9sYXRpbHVzIG1pY3JvcHMqIChibHVlbGluZSB0aWxlZmlzaCkgYW5kICpDbHVwZWEgaGFyZW5ndXMqCgoKYGBge3IgbG9hZF9kYXRhLCBldmFsID0gVCwgZWNobyA9IFR9CgojIFNwYXRpYWwgZGF0YQpTdGF0ZXMgPC0gYygibWFpbmUiLCAibmV3IGhhbXBzaGlyZSIsICJtYXNzYWNodXNldHRzIiwgImNvbm5lY3RpY3V0IiwgInJob2RlIGlzbGFuZCIsICJuZXcgeW9yayIsICJuZXcgamVyc2V5IiwgImRlbGF3YXJlIiwgIm1hcnlsYW5kIiwgInZpcmdpbmlhIiwgIm5vcnRoIGNhcm9saW5hIikgCgojIFVTIFN0YXRlIE1hcCAobGFuZCkKbGFuZF9zZiA8LSBzdF9hc19zZihtYXAoInN0YXRlIiwgcGxvdCA9IEZBTFNFLCBmaWxsID0gVFJVRSkpICU+JSAKICBmaWx0ZXIoSUQgJWluJSBTdGF0ZXMpICU+JSAKICBtdXRhdGUoYWJyZXYgPSBjKCJDVCIsIkRFIiwiTUUiLCJNRCIsIk1BIiwiTkgiLCJOSiIsIk5ZIiwiTkMiLCJSSSIsIlZBIiksCiAgICAgICAgIHN0YXRlID0gc3RyX3RvX3NlbnRlbmNlKElEKQogICAgICAgICApCgojIFVTIEVFWiBtYXAKcGF0aF93b3JsZCA8LSBteV9wYXRoKCJHIiwgZXh0cmFfcGF0aCA9ICJTcGF0aWFsL1NBVS9TQVVfU2hhcGVmaWxlIiwgbmFtZSA9ICJTQVVFRVpfSnVseTIwMTUuc2hwIikKCgojIyMgUHJldmlvdXNsbHkgY3JlYXRlZCBncmlkcyAKCmdyaWRzIDwtIG15X3BhdGgoIkQiLCAiU3BhdGlhbC9ncmlkX2Vlel9mcCIsIG5hbWUgPSAiZ3JpZF9lZXpfZnBfZGYuY3N2IiwgcmVhZCA9IFQpICU+JQogIG11dGF0ZSgKICAgIHNwYXRpYWwgPSAiZnAiCiAgKSAlPiUgCiAgYmluZF9yb3dzKAogICAgbXlfcGF0aCgiRCIsICJTcGF0aWFsL2dyaWRfZWV6X3N3IiwgbmFtZSA9ICJncmlkX2Vlel9zd19kZi5jc3YiLCByZWFkID0gVCkKICApICU+JSAKICBzZWxlY3QoLXNwcCkgJT4lIAogIG11dGF0ZSgKICAgIHNwYXRpYWwgPSBpZmVsc2UoaXMubmEoc3BhdGlhbCksInN3IixzcGF0aWFsKQogICkgJT4lIAogIGRpc3RpbmN0KC5rZWVwX2FsbCA9IFQpCiAgCgojIFNwZWNpZXMgZGF0YQoKIyBNYW5hZ2VkIHNwZWNpZXMgYnkgTWlkLUF0bGFudGljIENvdW5jaWwgTWFuYWdlbWVudCBQbGFucywgYW5kIFN0YXRlIHdhdGVycwojIGh0dHBzOi8vd3d3LmZpc2hlcmllcy5ub2FhLmdvdi9uZXctZW5nbGFuZC1taWQtYXRsYW50aWMvY29tbWVyY2lhbC1maXNoaW5nL25ldy1lbmdsYW5kLW1pZC1hdGxhbnRpYy1maXNoZXJ5LW1hbmFnZW1lbnQtcGxhbnMKClNwZWNpZXMgPC0gYygKICAiUGFyYWxpY2h0aHlzIGRlbnRhdHVzIiwgI3N1bW1lciBmbG91bmRlcgogICJTdGVub3RvbXVzIGNocnlzb3BzIiwgI1NjdXAiCiAgIkNlbnRyb3ByaXN0aXMgc3RyaWF0YSIjLCAjIGJsYWNrIHNlYSBiYXNzCiAgKQoKc3BwX3BhdGhzIDwtIGxpc3QuZmlsZXMobXlfcGF0aCgiUiIsZXh0cmFfcGF0aCA9ICJQYXJ0aWFsL0ludGVycG9sYXRpb24vIikpCgojIFNvbWUgZ2liaXJpcyBmb3IgbmFtZXMKdGF4b25fbGlzdCA8LSBnc3ViKCJfIiwiICIsc3BwX3BhdGhzKQp0YXhvbl9saXN0IDwtIGdzdWIoInRpZiAiLCIiLHRheG9uX2xpc3QpCnRheG9uX2xpc3QgPC0gZ3N1YigiLmNzdiIsIiIsdGF4b25fbGlzdCkKCnRheG9uX2xpc3QgPC0gdGF4b25fbGlzdFt0YXhvbl9saXN0ICVpbiUgU3BlY2llc10KCiMgTm93IHNldCBhIGxpc3Qgb2YgZmlsZXMgdG8gcmVhZAp0YXhvbl9yZWFkIDwtIHBhc3RlMCgidGlmXyIsdGF4b25fbGlzdCwiLmNzdiIpCnRheG9uX3JlYWQgPC0gZ3N1YigiICIsIl8iLHRheG9uX3JlYWQpCgp0YXhvbl9yZWFkIDwtIHNwcF9wYXRoc1tzcHBfcGF0aHMgJWluJSB0YXhvbl9yZWFkXQoKIyMjIyBMb2FkIHN3IGludGVycG9sYXRpb24gCgp0YXhvbl9zdyA8LSBteV9wYXRoKCJSIixleHRyYV9wYXRoID0gIlBhcnRpYWwvSW50ZXJwb2xhdGlvbi8iLCBuYW1lID0gdGF4b25fcmVhZCkKCiMgTG9hZCBhbGwgc3AgaW4gb25lIHRhYmxlCmhpc3RvcmljX3NwcCA8LSBiaW5kX3Jvd3MobGFwcGx5KHRheG9uX3N3LCBmcmVhZCkpICU+JSAKICBsZWZ0X2pvaW4oZ3JpZHMsCiAgICAgICAgICAgIGJ5ID0gYygiaW5kZXgiLCJsb24iLCJsYXQiKQogICkgJT4lCiAgZmlsdGVyKCFpcy5uYShzcGF0aWFsKSkgJT4lIAogIG11dGF0ZSgKICAgIHNlYXNvbiA9IGlmZWxzZShzdHJfZGV0ZWN0KHJlZ2lvbiwiU3ByaW5nIiksIlNwcmluZyIsIkZhbGwiKSwKICAgIGxhYmVsID0gaWZlbHNlKHNwcCA9PSAiUGFyYWxpY2h0aHlzIGRlbnRhdHVzIiAmIHllYXIgPj0gMTk4MCAmIHllYXIgPD0gMTk4NiwiUmVmZXJlbmNlIiwKICAgICAgICAgICAgICAgICAgIGlmZWxzZShzcHAgPT0gIlN0ZW5vdG9tdXMgY2hyeXNvcHMiICYgeWVhciA+PSAxOTg4ICYgeWVhciA8PSAxOTkyLCJSZWZlcmVuY2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZSggc3BwID09IkNlbnRyb3ByaXN0aXMgc3RyaWF0YSIgJiB5ZWFyID49IDE5ODAgJiB5ZWFyIDw9IDIwMDEsIlJlZmVyZW5jZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZSh5ZWFyID4gMjAwMSwiVG9kYXkiLE5BKQogICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICkKICAgICkKICApCgojIGhpc3RvcmljX3NwcCAlPiUgCiMgICBmaWx0ZXIoaXMubmEoc3BhdGlhbCkpICU+JSAKIyAgIGZpbHRlcih5ZWFyID09IDE5NzMsCiMgICAgICAgICAgcmVnaW9uID09ICJOb3J0aGVhc3QgVVMgRmFsbCIpICU+JSAKIyAgIGdncGxvdCgpICsKIyAgICAgZ2VvbV90aWxlKAojICAgICAgIGFlcygKIyAgICAgICAgIHggPSBsb24sCiMgICAgICAgICB5ID0gbGF0LAojICAgICAgICAgZmlsbCA9IGluZGV4CiMgICAgICAgKQojICAgICApICsKIyAgIGZhY2V0X2dyaWQoc3BwfnN0YXRlKSArIAojICAgZ2VvbV9zZihkYXRhID0gbGFuZF9zZixhZXMoKSkgKwojICAgZ2VvbV9zZihkYXRhID0gZWV6X3NmLCBhZXMoKSwgZmlsbCA9TkEpCgp1bmlxdWUoaGlzdG9yaWNfc3BwJHNwcCkKdW5pcXVlKGhpc3RvcmljX3NwcCRyZWdpb24pCnVuaXF1ZShoaXN0b3JpY19zcHAkc2Vhc29uKQoKIyBQZXJpb2RzCnBlcmlvZHMgPC10aWJibGUoCiAgb3JkZXIgPSBjKHJlcCgiYSIsMTIpLAogICAgICAgICAgICByZXAoImIiLDEyKSwKICAgICAgICAgICAgcmVwKCJjIiwxMiksCiAgICAgICAgICAgIHJlcCgiZCIsMTEpCiAgKSwKICBsYWJlbCA9IGMocmVwKCIxOTczLTE5ODQiLDEyKSwKICAgICAgICAgICAgcmVwKCIxOTg1LTE5OTYiLDEyKSwKICAgICAgICAgICAgcmVwKCIxOTk3LTIwMDgiLDEyKSwKICAgICAgICAgICAgcmVwKCIyMDA5LTIwMTkiLDExKQogICksCiAgeWVhciA9IGMoc2VxKDE5NzMsMTk4NCwxKSwKICAgICAgICAgICBzZXEoMTk4NSwxOTk2LDEpLAogICAgICAgICAgIHNlcSgxOTk3LDIwMDgsMSksCiAgICAgICAgICAgc2VxKDIwMDksMjAxOSwxKQogICkKICApCgoKc3RhdGVfbGF0IDwtIGhpc3RvcmljX3NwcCAlPiUKICBncm91cF9ieShzdGF0ZSkgJT4lIAogIHN1bW1hcmlzZSgKICAgIG9yZGVyID0gbWVhbihsYXQpCiAgKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShzdGF0ZSkpICU+JSAKICBtdXRhdGUoYWJyZXYgPSBjKCJDVCIsIkRFIiwiTUUiLCJNRCIsIk1BIiwiTkgiLCJOSiIsIk5ZIiwiTkMiLCJSSSIsIlZBIikKICApICU+JSAKICBhcnJhbmdlKGRlc2Mob3JkZXIpKSAlPiUgCiAgbXV0YXRlKGxhdCA9IG9yZGVyLAogICAgIyBvcmRlciA9IGxldHRlcnNbMToxMV0sCiAgICBvcmRlciA9IGMoImIiLCJhIixsZXR0ZXJzWzM6MTFdKSwpCgoKCiMgU3RhdGUgcGFsbGV0CgpzdGF0ZV9wYWxsZXQgPC0gYyh3ZXNfcGFsZXR0ZShuID0gNSwgbmFtZSA9ICJEYXJqZWVsaW5nMSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2VzX3BhbGV0dGUobiA9IDUsIG5hbWUgPSAiRGFyamVlbGluZzIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgd2VzX3BhbGV0dGUobiA9IDIsIG5hbWUgPSAiR3JhbmRCdWRhcGVzdDEiKQogICAgICAgICAgICAgICAgICAiI0ZENjQ2NyIKICAgICAgICAgICAgICAgICAgKQoKCgojIHByaW50IGZvciBub3RlYm9vawpoZWFkKGhpc3RvcmljX3NwcCkKYGBgCgoKIyMgUmVndWxhdG9yeSB1bml0cyByZXN1bHQKCmBgYHtyIGNyb3BwZWRfcGxvdF9wYXBlciwgZXZhbCA9IEYsIGVjaG8gPSBUfQoKIyMjIyBEYXRhIG5lZWRlZCAjIyMjCgojIEdldCBzdGF0ZSBvcmRlciBmcm9tIE5vcnRoIHRvIHNvdXRoCnN0YXRlX29yZGVyIDwtIG15X3BhdGgoIkQiLCJTcGF0aWFsL2dyaWRfZWV6X3N3IiwgbmFtZSA9ICJncmlkX2Vlel9zd19kZi5jc3YiLHJlYWQgPSBUKSAlPiUKICBncm91cF9ieShzdGF0ZSkgJT4lIAogIHN1bW1hcmlzZSgKICAgIG9yZGVyID0gbWVhbihsYXQpCiAgKSAlPiUgCiAgbXV0YXRlKGFicmV2ID0gYygiQ1QiLCJERSIsIk1FIiwiTUQiLCJNQSIsIk5IIiwiTkoiLCJOWSIsIk5DIiwiUkkiLCJWQSIpCiAgKSAlPiUgCiAgYXJyYW5nZShkZXNjKG9yZGVyKSkgJT4lIAogIG11dGF0ZShvcmRlcj0gYygiYiIsImEiLGxldHRlcnNbMzoxMV0pKSAlPiUgIyB3ZWlyZGx5IG1haW5lIGdvZXMgYmVsb3cKICBhcnJhbmdlKG9yZGVyKQoKCgojIExvYWQgZ3JpZCBvZiBzdGF0ZSB3YXRlcnMKZ3JpZF9lZXpfc3dfc2YgPC0gIHN0X3JlYWQobXlfcGF0aCgiRCIsIlNwYXRpYWwvZ3JpZF9lZXpfc3ciLCBuYW1lID0gImdyaWRfZWV6X3N3X3NmLnNocCIpKSAlPiUKICBzZWxlY3QoaW5kZXgsc3RhdGUsZ2VvbWV0cnkpICU+JSAKICBtdXRhdGUobWV0aG9kID0gInN0YXRlX3dhdGVycyIsCiAgICAgICAgIHN0YXRlID0gc3RyX3RvX3NlbnRlbmNlKHN0YXRlKSkgJT4lIAogIGxlZnRfam9pbihzdGF0ZV9vcmRlcikKCmdyaWRfZWV6X3N3X3NmJGdyb3VwIDwtIGZhY3RvcihncmlkX2Vlel9zd19zZiRhYnJldiwgICAgICAjIFJlb3JkZXJpbmcgZ3JvdXAgZmFjdG9yIGxldmVscwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gc3RhdGVfb3JkZXIkYWJyZXYpCgoKIyBMb2FkIGdyaWQgb2YgZmlzaGluZyBwb3J0cwpncmlkX2Vlel9mcF9zZiA8LSAgc3RfcmVhZChteV9wYXRoKCJEIiwiU3BhdGlhbC9ncmlkX2Vlel9mcCIsIG5hbWUgPSAiZ3JpZF9lZXpfZnAuc2hwIikpICU+JQogIHNlbGVjdChpbmRleCxhYnJldj1sbmRuZ19zLGdlb21ldHJ5KSAlPiUgCiAgbXV0YXRlKG1ldGhvZCA9ICJmaXNoaW5nX3BvcnQiIywKICAgICAgICAgIyBzdGF0ZSA9IHN0cl90b19zZW50ZW5jZShsYW5kaW5nX3BvcnQpCiAgICAgICAgICklPiUgCiAgbGVmdF9qb2luKHN0YXRlX29yZGVyKQoKCmdyaWRfZWV6X2ZwX3NmJGdyb3VwIDwtIGZhY3RvcihncmlkX2Vlel9mcF9zZiRhYnJldiwgICAgICAjIFJlb3JkZXJpbmcgZ3JvdXAgZmFjdG9yIGxldmVscwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gc3RhdGVfb3JkZXIkYWJyZXYpCgpncmlkX2Vlel9mcF9zZiA8LSBhcnJhbmdlKGdyaWRfZWV6X2ZwX3NmLGdyb3VwKQojIFBsb3R0aW5nIAojIE1ha2Ugc3VyZSBzdF9zaW1wbGlmeSgpIGlzIHJ1biBmb3IgZWV6IHNmCgojIFN0YXRlIHdhdGVycyBwbG90CgpwX3N3IDwtIGdyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlKAogICMgT3ZlcmFsbCAob3ZlcmxhcHBpbmcpIHBvc2l0aW9uCiAgZ2dwbG90KGdyaWRfZWV6X3N3X3NmKSArCiAgICBnZW9tX3NmKGRhdGEgPSBlZXpfc2YsIGFlcygpLCBmaWxsID0gIndoaXRlIikgKyAKICAgIGdlb21fc2YoYWVzKGNvbG9yID1ncm91cCAsIGZpbGwgPSBncm91cCksIGFscGhhID0gMC4zKSArCiAgICBnZW9tX3NmKGRhdGEgPSBsYW5kX3NmLCBhZXMoKSkgKwogICAgZ2dzZmxhYmVsOjpnZW9tX3NmX2xhYmVsX3JlcGVsKGRhdGEgPSBsYW5kX3NmLCBhZXMobGFiZWw9IGFicmV2KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYm94LnBhZGRpbmcgPSAwLjEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMSkgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHN0YXRlX3BhbGxldCkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gc3RhdGVfcGFsbGV0KSArCiAgICBteV9nZ3RoZW1lX3AobGVnX3BvcyA9ICIiLAogICAgICAgICAgICAgICAgIGF4X3R4X3MgPSAxMykgKwogICAgY29vcmRfc2YoeWxpbSA9IGMoMzAsNDgpKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gYygzMCwzNSw0MCw0NSkpKwogICAgbGFicyh4ID0gIiIsIHkgPSAiIiwgdGl0bGUgPSAiQSkgU3RhdGUgd2F0ZXJzIGFwcHJvYWNoIikgKwogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApKSwKICAjIFNob3dpbmcgZWFjaCBzdGF0ZSBzZXBhcmF0ZWx5CiAgZ2dwbG90KGdyaWRfZWV6X3N3X3NmKSArCiAgICBnZW9tX3NmKGRhdGEgPSBsYW5kX3NmLCBhZXMoKSwgZmlsbCA9ICJncmV5ODAiKSArCiAgICBnZW9tX3NmKGFlcyhjb2xvciA9IGdyb3VwKSxzaXplID0gMC4xLCBhbHBoYSA9IDAuMykgKwogICAgZmFjZXRfd3JhcCh+IGdyb3VwKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHN0YXRlX3BhbGxldCwKICAgICAgICAgICAgICAgICAgICAgICAjIGxhYmVscyA9IHVuaXF1ZShncmlkX2Vlel9zd19zZiRncm91cCkpICsKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBncmlkX2Vlel9zd19zZiAlPiUgYXJyYW5nZShvcmRlcikgJT4lICBwdWxsKHN0YXRlKSAlPiUgdW5pcXVlKCkpICsKICAgIGdndGl0bGUoIiIpICsKICAgIG15X2dndGhlbWVfcChsZWdfcG9zID0gIiIsCiAgICAgICAgICAgICAgICAgYXhfdHhfcyA9IDExLAogICAgICAgICAgICAgICAgIGF4eF90eF9hbmcgPSA0NSwKICAgICAgICAgICAgICAgICBoanVzdCA9IDEKICAgICksCiAgbnJvdyA9IDEpCgoKIyMjIyMgLS0tLS0tLS0tLS0tLSAjIyMjCiMgRmlzaGluZyBQb3J0cyBwbG90CiMjIyMjIC0tLS0tLS0tLS0tLS0gIyMjIwoKCmdyaWRfZWV6X2ZwX3NmIDwtCiAgZ3JpZF9lZXpfc3dfc2YgJT4lIAogIGZpbHRlcighZ3JvdXAgJWluJSBncmlkX2Vlel9mcF9zZiRncm91cCkgJT4lIAogIG11dGF0ZShpbmRleCA9IE5BKSAlPiUgCiAgYmluZF9yb3dzKGdyaWRfZWV6X2ZwX3NmKQogIAogIAoKCnBfZnAgPC0gZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UoCiAgIyBPdmVyYWxsIChvdmVybGFwcGluZykgcG9zaXRpb24KICBnZ3Bsb3QoZGF0YSA9IHN1YnNldChncmlkX2Vlel9mcF9zZiwgaW5kZXggIT0gIk5BIikpICsKICAgIGdlb21fc2YoZGF0YSA9IGVlel9zZiwgYWVzKCksIGZpbGwgPSAid2hpdGUiKSArIAogICAgZ2VvbV9zZihhZXMoY29sb3IgPSBncm91cCwgZmlsbCA9IGFicmV2KSwgYWxwaGEgPSAwLjMpICsKICAgIGdlb21fc2YoZGF0YSA9IGxhbmRfc2YsIGFlcygpKSArCiAgICBnZ3NmbGFiZWw6Omdlb21fc2ZfbGFiZWxfcmVwZWwoZGF0YSA9IGxhbmRfc2YsIGFlcyhsYWJlbD0gYWJyZXYpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gNCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3gucGFkZGluZyA9IDAuMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxKSArCiAgICAjIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBzdGF0ZV9wYWxsZXQpICsKICAgICMgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gc3RhdGVfcGFsbGV0KSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYyhzdGF0ZV9wYWxsZXRbMzo0XSxzdGF0ZV9wYWxsZXRbNjoxM10pKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKHN0YXRlX3BhbGxldFszOjRdLHN0YXRlX3BhbGxldFs2OjEzXSkpICsKICAgIG15X2dndGhlbWVfcChsZWdfcG9zID0gIiIsCiAgICAgICAgICAgICAgICAgYXhfdHhfcyA9IDEzKSArCiAgICBjb29yZF9zZih5bGltID0gYygzMCw0OCkpICsKICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBjKDMwLDM1LDQwLDQ1KSkgKwogICAgbGFicyh4ID0gIiIsIHkgPSAiIiwgdGl0bGUgPSAiQikgRmlzaGluZyBwb3J0cyBhcHByb2FjaCIpICsKICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSksCiAgIyBTaG93aW5nIGVhY2ggc3RhdGUgc2VwYXJhdGVseQogIGdncGxvdCgpICsKICAgIGdlb21fc2YoZGF0YSA9IHN1YnNldChncmlkX2Vlel9mcF9zZiwgaW5kZXggPSAiTkEiKSwgY29sb3IgPSAid2hpdGUiKSArCiAgICBnZW9tX3NmKGRhdGEgPSBzdWJzZXQoZ3JpZF9lZXpfZnBfc2YsIGluZGV4ICE9ICJOQSIpLCBhZXMoY29sb3IgPSBncm91cCksc2l6ZSA9IDAuMSwgYWxwaGEgPSAwLjMpICsKICAgIGdlb21fc2YoZGF0YSA9IGxhbmRfc2YsIGFlcygpLCBmaWxsID0gImdyZXk4MCIpICsKICAgIGZhY2V0X3dyYXAofiBncm91cCkgKwogICAgZ2VvbV9wb2ludChkYXRhID0gcmVuYW1lKHBvcnRzX2RmLCBncm91cCA9IGxhbmRpbmdfc3RhdGUpLCBhZXMoeCA9IGxvbiwgeSA9IGxhdCksIGNvbG9yID0gIiNFNkEwQzQiKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKwogICAgIyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gc3RhdGVfcGFsbGV0LAogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoc3RhdGVfcGFsbGV0WzM6NF0sc3RhdGVfcGFsbGV0WzY6MTNdKSwKICAgICAgICAgICAgICAgICAgICAgICAjIGxhYmVscyA9IHVuaXF1ZShncmlkX2Vlel9mcF9zZiRncm91cCkpICsKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBncmlkX2Vlel9mcF9zZiAlPiUgYXJyYW5nZShvcmRlcikgJT4lICBwdWxsKHN0YXRlKSAlPiUgdW5pcXVlKCkpICsKICAgIGdndGl0bGUoIiIpICsKICAgIG15X2dndGhlbWVfcChsZWdfcG9zID0gIiIsCiAgICAgICAgICAgICAgICAgYXhfdHhfcyA9IDExLAogICAgICAgICAgICAgICAgIGF4eF90eF9hbmcgPSA0NSwKICAgICAgICAgICAgICAgICBoanVzdCA9IDEKICAgICksCiAgbnJvdyA9IDEpCgoKCmNvbWJpbmVkX3Bsb3QgPC0gZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UocF9zdyxwX2ZwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvdHRvbSA9ICJMb25naXR1ZGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZnQgPSAiTGF0aXR1ZGUiKQoKZ2dzYXZlKGZpbGVuYW1lID0gImJ1ZmZlcl9maWd1cmUuanBnIiwKICAgICAgIHBsb3QgPSBjb21iaW5lZF9wbG90LAogICAgICAgcGF0aCA9IG15X3BhdGgoIlIiLCJGaWd1cmVzIiksCiAgICAgICB3aWR0aCA9IDExLAogICAgICAgaGVpZ2h0ID0gMTEKICAgICAgICkKCmBgYAoKIyMgSW50ZXJwb2xhdGlvbiByZXN1bHQKCmBgYHtyfQoKIyBJbnRlcnBvbGF0aW9uIGRhdGEKaW50ZXJwb2xfcmVzdWx0IDwtIGhpc3RvcmljX3NwcCAlPiUgCiAgZmlsdGVyKCFpcy5uYShsYWJlbCkpICU+JSAKICBncm91cF9ieShsYWJlbCxpbmRleCxzcHAsc2Vhc29uLGxhdCxsb24pICU+JSAKICBzdW1tYXJpc2UobWVhbl9jcHVlID0gbWVhbih2YWx1ZSxuYS5ybT1UKSkgJT4lIAogIGZpbHRlcighaXMubmEobWVhbl9jcHVlKSkKCgojIFBhcGVyIG51bWJlcnMKCiMgaW50ZXJwb2xfcmVzdWx0ICU+JSAKIyAgIGZpbHRlcihtZWFuX2NwdWUgPjApICU+JSAKIyAgIFZpZXcoKQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0gIwojIEJpb21hc3MgQ2VudHJvaWQgc2hpZnQKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0gIwoKIyBFc3RpbWF0ZSB0b3RhbCBpbnRlcnBvbGF0aW9uCnRvdGFsX2ludGVyIDwtIGhpc3RvcmljX3NwcCAlPiUgCiAgZmlsdGVyKCFpcy5uYShsYWJlbCkpICU+JSAKICBncm91cF9ieShzcHAsaW5kZXgsc2Vhc29uKSAlPiUgCiAgc3VtbWFyaXNlKG1lYW5fY3B1ZSA9IG1lYW4odmFsdWUsbmEucm09VCkpICU+JSAKICBncm91cF9ieShzcHAsc2Vhc29uKSAlPiUgCiAgc3VtbWFyaXNlKHRvdGFsX2NwdWUgPSBzdW0obWVhbl9jcHVlLCBuYS5ybSA9IFQpKQoKCiMgRXN0aW1hdGUgY2VudHJvaWQgYmFzZWQgb24gdG9wIDEwIGdyaWRzIHdpdGggaGlnZXIgYWJ1bmRhbmNlCmNlbnRyb2lkX2RiIDwtIGhpc3RvcmljX3NwcCAlPiUgCiAgZmlsdGVyKCFpcy5uYShsYWJlbCkpICU+JSAKICBncm91cF9ieShsYWJlbCxpbmRleCxzcHAsc2Vhc29uLGxhdCxsb24pICU+JSAKICBzdW1tYXJpc2UobWVhbl9jcHVlID0gbWVhbih2YWx1ZSxuYS5ybT1UKSkgJT4lIAogIGZpbHRlcighaXMubmEobWVhbl9jcHVlKSkgJT4lIAogIGxlZnRfam9pbih0b3RhbF9pbnRlcikgJT4lIAogIG11dGF0ZSgKICAgIHBlcl9jcHVlID0gcm91bmQoKG1lYW5fY3B1ZS90b3RhbF9jcHVlKSoxMDAsMikKICApICU+JSAKICBncm91cF9ieShzcHAsbGFiZWwsc2Vhc29uKSAlPiUgCiAgdG9wX24oMTAscGVyX2NwdWUpICU+JSAKICBncm91cF9ieShzcHAsbGFiZWwsc2Vhc29uKSAlPiUgCiAgc3VtbWFyaXNlKAogICAgbGF0ID0gbWVhbihsYXQpLAogICAgbG9uID0gbWVhbihsb24pCiAgKQoKIyBQYXBlciBudW1iZXJzCiMgY2VudHJvaWRfZGIgJT4lIAojICAgc2VsZWN0KC1sb24pICU+JSAKIyAgIHNwcmVhZChsYWJlbCxsYXQpICU+JSAKIyAgIG11dGF0ZShkaWZmID0gVG9kYXktUmVmZXJlbmNlKSAlPiUgCiMgICBWaWV3KCkKCgojIEZvciBhbHRlcm5hdGl2ZSBjb2xvciBwYWxsZXQKcGFsIDwtIHdlc19wYWxldHRlKCJaaXNzb3UxIiwxMDAsdHlwZSA9ICJjb250aW51b3VzIikKCmludGVyX21hcCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV90aWxlKGRhdGEgPSBzdWJzZXQoaW50ZXJwb2xfcmVzdWx0LCBtZWFuX2NwdWUgPT0gMCksCiAgICAgICAgICAgIGFlcygKICAgICAgICAgICAgICB4ID0gbG9uLAogICAgICAgICAgICAgIHkgPSBsYXQKICAgICAgICAgICAgKSwKICAgICAgICAgICAgZmlsbCA9ICJncmV5OTAiLAogICAgICAgICAgICBjb2xvciA9ICJncmV5OTAiCiAgKSArIAogIGdlb21fdGlsZShkYXRhID0gc3Vic2V0KGludGVycG9sX3Jlc3VsdCwgbWVhbl9jcHVlID4gMCksCiAgICAgICAgICAgIGFlcygKICAgICAgICAgICAgICB4ID0gbG9uLAogICAgICAgICAgICAgIHkgPSBsYXQsCiAgICAgICAgICAgICAgZmlsbCA9IGxvZzEwKG1lYW5fY3B1ZSksCiAgICAgICAgICAgICAgY29sb3IgPSBsb2cxMChtZWFuX2NwdWUpCiAgICAgICAgICAgICAgIyBmaWxsID0gbWVhbl9jcHVlLAogICAgICAgICAgICAgICMgY29sb3IgPSBtZWFuX2NwdWUKICAgICAgICAgICAgKQogICkgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBjZW50cm9pZF9kYiwKICAgICAgICAgICAgIGFlcygKICAgICAgICAgICAgICAgeCA9IGxvbiwKICAgICAgICAgICAgICAgeSA9IGxhdAogICAgICAgICAgICAgKSwKICAgICAgICAgICAgIHNoYXBlID0gMywKICAgICAgICAgICAgIGNvbG9yID0gIndoaXRlIgogICkgKyAKICBnZW9tX3NmKGRhdGEgPSBsYW5kX3NmLGFlcygpKSArCiAgbGFicyh4ID0gIkxvbmdpdHVkZSIsCiAgICAgICB5ID0gIkxhdGl0dWRlIikgKwogICMgZ2dzZmxhYmVsOjpnZW9tX3NmX2xhYmVsX3JlcGVsKGRhdGEgPSBsYW5kX3NmLCBhZXMobGFiZWw9IGFicmV2KSwgCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gNCwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJveC5wYWRkaW5nID0gMC4xMCwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMSkgKwogICMgVmlyaWRpcyBvcHRpb24KIyBzY2FsZV9maWxsX3ZpcmlkaXMoIkNQVUUiLAojICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDAsNDApLAojICAgICAgICAgICAgICAgICAgICAjIGxpbWl0cyA9IGMoLTUsMSksICMgZm9yIGxvZzEwCiMgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9IC0xLAojICAgICAgICAgICAgICAgICAgICAgZW5kID0gMC45CiMgICAgICAgICAgICAgICAgICAgICkgKwojIHNjYWxlX2NvbG9yX3ZpcmlkaXMoIkNQVUUiLAojICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLDQwKSwKIyAgICAgICAgICAgICAgICAgICAgICMgbGltaXRzID0gYygtNSwxKSwgIyBmb3IgbG9nMTAKIyAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9IC0xLAojICAgICAgICAgICAgICAgICAgICAgZW5kID0gMC45CiMgICAgICAgICAgICAgICAgICAgICApICsKIyB3ZXMgYW5kZXJzb24gb3B0aW9uCnNjYWxlX2ZpbGxfZ3JhZGllbnRuKCJDUFVFIiwKICAgICAgICAgICAgICAgICAgICAgY29sb3VycyA9IHBhbCwKICAgICAgICAgICAgICAgICAgICAgIyBsaW1pdHMgPSBjKDAsNDApICMgRm9yIGNwdWUKICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygtNSwxKSAjIGZvciBsb2cxMAoKKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKCJDUFVFIiwKICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VycyA9IHBhbCwKICAgICAgICAgICAgICAgICAgICAgICAgIyBsaW1pdHMgPSBjKDAsNDApICMgZm9yIGNwdWUKICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygtNSwxKSAjIGZvciBsb2cxMAogICkgKwogIGZhY2V0X2dyaWQoc3BwfnNlYXNvbitsYWJlbCkgKwogIG15X2dndGhlbWVfbShtYXBfdHlwZSA9ICJuYSIsIGxlZ19wb3MgPSAicmlnaHQiLGF4X3R4X3MgPSA3LGF4X3RsX3MgPSAxMCxsZWdfdHhfcyA9IDEyKSAjKwojIHRoZW1lKGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDMsImxpbmUiKSkKCgpnZ3NhdmUoImludGVycG9sYXRpb25fd2EuanBnIiwKICAgICAgIGludGVyX21hcCwKICAgICAgIHBhdGggPSBteV9wYXRoKCJSIiwiRmlndXJlcyIpLAogICAgICAgd2lkdGggPSA5LAogICAgICAgaGVpZ2h0ID0gNykKCmBgYAoKCiMjIEF2ZXJhZ2UgcHJvcG9ydGlvbgoKVGhpcyBtYXAgc2hvd3MgdGhlIGFnZ3JlZ2F0ZWQgZXh0cmFwb2xhdGVkIHZhbHVlIGZyb20gYWxsIHRocmVlIHNwZWNpZXMgcGVyIFN0YXRlIGF2ZXJhZ2UgYWNyb3NzIHRoZSB3aG9sZSBzdHVkeSBwZXJpb2Qgd2l0aGluIGVhY2ggU3RhdGUncyB3YXRlci4KCipOb3RlOiogVGhpcyBpcyBpbnRlbmRlZCB0byBiZSBhIHN1cHBsZW1lbnRhbCBmaWd1cmUKCmBgYHtyIGFyZWFfbWFwX3N0YXRlLCBldmFsID0gVCwgZWNobyA9IFQsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMn0KCmRhdGFfZ3JpZCA8LSBoaXN0b3JpY19zcHAgJT4lIAogIGdyb3VwX2J5KHN0YXRlLGxhdCxsb24scmVnaW9uLHNwYXRpYWwpICU+JSAKICBzdW1tYXJpc2Uoc3VtID0gc3VtKHZhbHVlLG5hLnJtPSBUKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lICMgc3VtIG9mIGFsbCBzcGVjaWVzCiAgZ3JvdXBfYnkoc3RhdGUsbGF0LGxvbixyZWdpb24sc3BhdGlhbCkgJT4lIAogIHN1bW1hcmlzZShtZWFuID0gbWVhbihzdW0sbmEucm09IFQpLCAuZ3JvdXBzID0gImRyb3AiKSAjIGF2ZXJhZ2Ugb2YgYWxsIHllYXJzCgoKZ2dwbG90KGRhdGEgPSBzdWJzZXQoZGF0YV9ncmlkLCAhaXMubmEobWVhbikpKSArCiAgZ2VvbV90aWxlKAogICAgYWVzKAogICAgICB4ID0gbG9uLAogICAgICB5ID0gbGF0LAogICAgICBmaWxsID0gbWVhbiwKICAgICAgY29sID0gbWVhbgogICAgKQogICkgKwogIGdlb21fc2YoZGF0YSA9IGxhbmRfc2YsIGFlcygpKSArCiAgZmFjZXRfd3JhcCh+IHN0YXRlICArICByZWdpb24gKyBzcGF0aWFsKSArCiAgbGFicyh4ID0gIkxvbmdpdHVkZSIsIHkgPSAiTGF0aXR1ZGUiKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzKCJNZWFuIEludGVycG9sYXRpb24iLCBhbHBoYSA9IDAuOCkgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXMoIk1lYW4gSW50ZXJwb2xhdGlvbiIsIGFscGhhID0gMC44KSArCiAgdGhlbWVfYncoKQpgYGAKCiMjIFByb3BvcnRpb24gQ2hhbmdlCgpIZXJlIHdlIHNob3cgdGhlIGF2ZXJhZ2UgcHJvcG9ydGlvbiBvZiB0aGUgaW50ZXJwb2xhdGlvbiBieSBTdGF0ZSBhbmQgdGltZSBwZXJpb2QuIFRpbWUgcGVyaW9kcyB3ZXJlIGFyYml0cmFyeSBkZWZpbmVkIGFzOwoKLSBFYXJseTsgMTk3MyB0byAxOTg0Ci0gTWlkOyAxOTg1IHRvIDE5OTcKLSBMYXRlOyAxOTk4IHRvIDIwMTEKLSBOb3c7IDIwMTIgdG8gMjAxOQoKKk5vdGVzOiogRmlndXJlIHJlcHJlc2VudHMgdGhlICoqU3ByaW5nKiogc3VydmV5LiBUaGlzIGNvbXB1dGF0aW9uIGNvbnNpZGVycyB0aGUgT3ZlcmxhcHBpbmcgb2Ygc3RhdGUgd2F0ZXJzLgoKIyMjIERhdGEgcHJlcGFyYXRpb24KCmBgYHtyIGRhdGFfcHJlcCwgZXZhbCA9IEYsIGVjaG8gPSBULCByZXN1bHRzPSdoaWRlJ30KCgp0b3RhbF9maXRlZCA8LSBoaXN0b3JpY19zcHAgJT4lIAogIGdyb3VwX2J5KHllYXIsc2Vhc29uLHNwcCxzcGF0aWFsKSAlPiUgCiAgc3VtbWFyaXNlKHRvdGFsX3ZhbHVlID0gc3VtKHZhbHVlLG5hLnJtPVQpLC5ncm91cHMgPSAiZHJvcCIpCgoKc3RhdGVfZml0IDwtIGhpc3RvcmljX3NwcCAlPiUgCiAgZ3JvdXBfYnkoc3RhdGUseWVhcixsYWJlbCxzZWFzb24sc3BwLHNwYXRpYWwpICU+JSAKICBzdW1tYXJpc2Uoc3RhdGVfdmFsdWUgPSBzdW0odmFsdWUsbmEucm09IFQpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgIyBWaWV3KCkKICBsZWZ0X2pvaW4odG90YWxfZml0ZWQsCiAgICAgICAgICAgIGJ5ID0gYygieWVhciIsInNlYXNvbiIsInNwcCIsInNwYXRpYWwiKSkgJT4lCiAgbXV0YXRlKHBlcmNlbnRhZ2UgPSBzdGF0ZV92YWx1ZS90b3RhbF92YWx1ZSoxMDApICU+JSAKICBncm91cF9ieShzdGF0ZSxsYWJlbCxzZWFzb24sc3BwLHNwYXRpYWwpICU+JSAKICBzdW1tYXJpc2UobWVhbl9wZXIgPSByb3VuZChtZWFuKHBlcmNlbnRhZ2UpKSwuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgI09ubHkgc2hvdyByZXN1bHRzIGZvciBzcHJpbmcKICBmaWx0ZXIoIWlzLm5hKGxhYmVsKSkKCmBgYAoKIyMjIyBSZWd1bGF0b3J5IHVuaXRzIG1hcAoKYGBge3IgcmVnX3VuaXRfbWFwX2RpZmYsIGV2YWwgPSBGLCBlY2hvID0gVCwgcmVzdWx0cz0naGlkZSd9CgpyZWdfdW5pdCA8LSBzdGF0ZV9maXQgJT4lIAogIGZpbHRlcihzZWFzb24gPT0gIlNwcmluZyIpICU+JSAKICBzcHJlYWQoc3BhdGlhbCxtZWFuX3BlcikgJT4lIAogICMgU2V0IE5BJ3MgdG8gMCBiZWNhdXNlIG5vIGRhdGEgZm91bmQgb24gRlAKICBtdXRhdGUoZnAgPSByZXBsYWNlX25hKGZwLDApKSAlPiUgCiAgIyBWaWV3KCkKICBtdXRhdGUoCiAgICBkaWZmZXJlbmNlID0gYWJzKGZwLXN3KSwKICAgIGRpZmZlcmVuY2UgPSBpZmVsc2UoZGlmZmVyZW5jZSA+IDEwMCwxMDAsCiAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkaWZmZXJlbmNlIDwgLTEwMCwtMTAwLGRpZmZlcmVuY2UpCiAgICApCiAgKSAlPiUgCiAgZ2F0aGVyKCJzcGF0aWFsIiwibWVhbl9wZXIiLGZwOmRpZmZlcmVuY2UpICU+JSAKICBtdXRhdGUoc3BwID0gZ3N1YigiICIsIlxuIixzcHApLAogICAgICAgICBzcGF0aWFsID0gaWZlbHNlKHNwYXRpYWwgPT0gImZwIiwiRmlzaGluZyBwb3J0cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHNwYXRpYWwgPT0gInN3IiwiU3RhdGUgd2F0ZXJzIiwiRGlmZmVyZW5jZSIpCiAgICAgICAgICkKICApCgoKIyBUaGUgcGxvdAptYXBfcGxvdCA8LSBsYW5kX3NmICU+JSAKICBsZWZ0X2pvaW4ocmVnX3VuaXQsCiAgICAgICAgICAgIGJ5ID0gInN0YXRlIikgJT4lIAogIGZpbHRlcihzcGF0aWFsICE9ICJEaWZmZXJlbmNlIikgJT4lIAogIGdncGxvdCgpICsKICBnZW9tX3NmKGFlcyhmaWxsID0gbWVhbl9wZXIpKSArCiAgdmlyaWRpczo6c2NhbGVfZmlsbF92aXJpZGlzKCJBdmVyYWdlIHByb3BvcnRpb24gcGVyIFN0YXRlIiwgYWxwaGEgPSAwLjgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMCwzNSw1KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzPShjKDAsMzUpKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICApKwogIGZhY2V0X2dyaWQoc3BhdGlhbH4gc3BwK2xhYmVsKSArCiAgbGFicyh4ID0gIiIsIAogICAgICAgeSA9ICIiKSArCiAgbXlfZ2d0aGVtZV9wKGZhY2V0X3R4X3MgPSAyMCwKICAgICAgICAgICAgICAgbGVnX3BvcyA9ICJib3R0b20iLAogICAgICAgICAgICAgICBheHhfdHhfYW5nID0gNDUsCiAgICAgICAgICAgICAgIGF4X3R4X3MgPSAxMiwKICAgICAgICAgICAgICAgYXhfdGxfcyA9IDE4LAogICAgICAgICAgICAgICBoanVzdCA9IDEpICsKICB0aGVtZShsZWdlbmQua2V5LndpZHRoID0gdW5pdCg0LCJsaW5lIikpIAoKCmRpZmZfcGxvdCA8LSBsYW5kX3NmICU+JSAKICBsZWZ0X2pvaW4ocmVnX3VuaXQsCiAgICAgICAgICAgIGJ5ID0gInN0YXRlIikgJT4lIAogIGZpbHRlcihzcGF0aWFsID09ICJEaWZmZXJlbmNlIikgJT4lIAogIGdncGxvdCgpICsKICBnZW9tX3NmKGFlcyhmaWxsID0gbWVhbl9wZXIpKSArCiAgdmlyaWRpczo6c2NhbGVfZmlsbF92aXJpZGlzKCJEaWZmZXJlbmNlICglKSIsIGFscGhhID0gMC44LG9wdGlvbiA9ICJDIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKDAsMjAsNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cz0oYygwLDIyKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbGFiZWxzID0gYygiPC0xMCIsc2VxKC03NSw3NSwyNSksIj4xMDAiKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICsKICBmYWNldF9ncmlkKHNwYXRpYWx+IHNwcCtsYWJlbCkgKwogIGxhYnMoeCA9ICIiLCAKICAgICAgIHkgPSAiIikgKwogIG15X2dndGhlbWVfcChmYWNldF90eF9zID0gMjAsCiAgICAgICAgICAgICAgIGxlZ19wb3MgPSAiYm90dG9tIiwKICAgICAgICAgICAgICAgYXh4X3R4X2FuZyA9IDQ1LAogICAgICAgICAgICAgICBheF90eF9zID0gMTIsCiAgICAgICAgICAgICAgIGF4X3RsX3MgPSAxOCwKICAgICAgICAgICAgICAgaGp1c3QgPSAxKSArCiAgdGhlbWUobGVnZW5kLmtleS53aWR0aCA9IHVuaXQoNCwibGluZSIpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF9ibGFuaygpCiAgICAgICAgKSAKCgojIENvd3Bsb3Qgb3B0aW9uCnAgPC0gZ2dkcmF3KCkgKwogICMgUmV2ZW51ZSBjaXJjdWxhcgogIGRyYXdfcGxvdChtYXBfcGxvdCwgeCA9IDAsIHkgPSAwLjIsIHdpZHRoID0gMSwgaGVpZ2h0ID0gMC44KSArCiAgIyBDYXRjaCBjaXJjdWxhcgogIGRyYXdfcGxvdChkaWZmX3Bsb3QsIHggPSAwLCB5ID0gMCwgd2lkdGggPSAxLCBoZWlnaHQgPSAwLjQpICsKICBkcmF3X3Bsb3RfbGFiZWwobGFiZWwgPSBjKCJMYXRpdHVkZSIsICJMb25naXR1ZGUiKSwgCiAgICAgICAgICAgICAgICAgIHNpemUgPSAxOCwKICAgICAgICAgICAgICAgICAgYW5nbGUgPSBjKDkwLDApLAogICAgICAgICAgICAgICAgICB4ID0gYygwLDAuNDUpLCAKICAgICAgICAgICAgICAgICAgeSA9IGMoMC40NSwwLjE1KQogICkKICAKCnNhdmVfcGxvdCgKICBwYXRoID0gbXlfcGF0aCgiUiIsIkZpZ3VyZXMiKSwKICAicHJvcG9ydGlvbl9jaGdfcmVnLmpwZyIsCiAgcCwKICBiYXNlX2hlaWdodCA9IDE0LAogIGJhc2Vfd2lkdGggPSAxNAopCgpyZWdfdW5pdCAlPiUgCiAgIyBmaWx0ZXIoc3BhdGlhbCA9PSAiZnAiKSAlPiUKICBzZWxlY3QoLWZwKSAlPiUgCiAgc3ByZWFkKGxhYmVsLHN3KSAlPiUgCiAgbXV0YXRlKAogICAgZGlmZmVyZW5jZSA9IFRvZGF5LVJlZmVyZW5jZQogICAgKSAlPiUgCiAgZ3RoZXIoUmVmZXJlbmNlOmRpZmZlcmVuY2UpCgpgYGAKCiMjIyMgU2Vhc29uYWwgdW5pdHMgbWFwCgpgYGB7ciBzZWFfdW5pdF9tYXBfZGlmZiwgZXZhbCA9IEYsIGVjaG8gPSBULCByZXN1bHRzPSdoaWRlJ30KCiMgR2V0IHNlYXNvbmFsIGRhdGEKc2Vhc29uX2ZpdCA8LSBzdGF0ZV9maXQgJT4lIAogIGZpbHRlcihzcGF0aWFsICE9ICJmcCIpICU+JQogIHNwcmVhZChzZWFzb24sbWVhbl9wZXIpICU+JQogIG11dGF0ZSgKICAgIERpZmZlcmVuY2UgPSBhYnMoRmFsbC1TcHJpbmcpLAogICAgRGlmZmVyZW5jZSA9IGlmZWxzZShEaWZmZXJlbmNlID4gMTAwLDEwMCwKICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKERpZmZlcmVuY2UgPCAtMTAwLC0xMDAsRGlmZmVyZW5jZSkKICAgICkKICApICU+JSAKICBnYXRoZXIoInNlYXNvbiIsIm1lYW5fcGVyIixGYWxsOkRpZmZlcmVuY2UpICU+JSAKICBtdXRhdGUoc3BwID0gZ3N1YigiICIsIlxuIixzcHApKQoKIyBUaGUgcGxvdAptYXBfcGxvdCA8LSBsYW5kX3NmICU+JSAKICBsZWZ0X2pvaW4oc2Vhc29uX2ZpdCwKICAgICAgICAgICAgYnkgPSAic3RhdGUiKSAlPiUgCiAgZmlsdGVyKHNlYXNvbiAhPSAiRGlmZmVyZW5jZSIpICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV9zZihhZXMoZmlsbCA9IG1lYW5fcGVyKSkgKwogIHZpcmlkaXM6OnNjYWxlX2ZpbGxfdmlyaWRpcygiQXZlcmFnZSBwcm9wb3J0aW9uIHBlciBTdGF0ZSIsIGFscGhhID0gMC44LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKDAsMTUsNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cz0oYygwLDE1KSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSsKICBmYWNldF9ncmlkKHNlYXNvbn4gc3BwK2xhYmVsKSArCiAgbGFicyh4ID0gIiIsIAogICAgICAgeSA9ICIiKSArCiAgbXlfZ2d0aGVtZV9wKGZhY2V0X3R4X3MgPSAyMCwKICAgICAgICAgICAgICAgbGVnX3BvcyA9ICJib3R0b20iLAogICAgICAgICAgICAgICBheHhfdHhfYW5nID0gNDUsCiAgICAgICAgICAgICAgIGF4X3R4X3MgPSAxMiwKICAgICAgICAgICAgICAgYXhfdGxfcyA9IDE4LAogICAgICAgICAgICAgICBoanVzdCA9IDEpICsKICB0aGVtZShsZWdlbmQua2V5LndpZHRoID0gdW5pdCg0LCJsaW5lIikpIAoKCmRpZmZfcGxvdCA8LSBsYW5kX3NmICU+JSAKICBsZWZ0X2pvaW4oc2Vhc29uX2ZpdCwKICAgICAgICAgICAgYnkgPSAic3RhdGUiKSAlPiUgCiAgZmlsdGVyKHNlYXNvbiA9PSAiRGlmZmVyZW5jZSIpICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV9zZihhZXMoZmlsbCA9IG1lYW5fcGVyKSkgKwogIHZpcmlkaXM6OnNjYWxlX2ZpbGxfdmlyaWRpcygiRGlmZmVyZW5jZSAoJSkiLCBhbHBoYSA9IDAuOCxvcHRpb24gPSAiQyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgwLDUsMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cz0oYygwLDUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBsYWJlbHMgPSBjKCI8LTEwIixzZXEoLTc1LDc1LDI1KSwiPjEwMCIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgKwogIGZhY2V0X2dyaWQoc2Vhc29ufiBzcHArbGFiZWwpICsKICBsYWJzKHggPSAiIiwgCiAgICAgICB5ID0gIiIpICsKICBteV9nZ3RoZW1lX3AoZmFjZXRfdHhfcyA9IDIwLAogICAgICAgICAgICAgICBsZWdfcG9zID0gImJvdHRvbSIsCiAgICAgICAgICAgICAgIGF4eF90eF9hbmcgPSA0NSwKICAgICAgICAgICAgICAgYXhfdHhfcyA9IDEyLAogICAgICAgICAgICAgICBheF90bF9zID0gMTgsCiAgICAgICAgICAgICAgIGhqdXN0ID0gMSkgKwogIHRoZW1lKGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDQsImxpbmUiKSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKQogICAgICAgICkgCgoKIyBDb3dwbG90IG9wdGlvbgpwIDwtIGdnZHJhdygpICsKICAjIFJldmVudWUgY2lyY3VsYXIKICBkcmF3X3Bsb3QobWFwX3Bsb3QsIHggPSAwLCB5ID0gMC4yLCB3aWR0aCA9IDEsIGhlaWdodCA9IDAuOCkgKwogICMgQ2F0Y2ggY2lyY3VsYXIKICBkcmF3X3Bsb3QoZGlmZl9wbG90LCB4ID0gMCwgeSA9IDAsIHdpZHRoID0gMSwgaGVpZ2h0ID0gMC40KSArCiAgZHJhd19wbG90X2xhYmVsKGxhYmVsID0gYygiTGF0aXR1ZGUiLCAiTG9uZ2l0dWRlIiksIAogICAgICAgICAgICAgICAgICBzaXplID0gMTgsCiAgICAgICAgICAgICAgICAgIGFuZ2xlID0gYyg5MCwwKSwKICAgICAgICAgICAgICAgICAgeCA9IGMoMCwwLjQ1KSwgCiAgICAgICAgICAgICAgICAgIHkgPSBjKDAuNDUsMC4xNSkKICApCiAgCgpzYXZlX3Bsb3QoCiAgcGF0aCA9IG15X3BhdGgoIlIiLCJGaWd1cmVzIiksCiAgInByb3BvcnRpb25fY2hnX3NlYXNfLmpwZyIsCiAgcCwKICBiYXNlX2hlaWdodCA9IDE0LAogIGJhc2Vfd2lkdGggPSAxNAopCgpgYGAKCiMjIEFyZWEgcGxvdAoKVGhpcyBncmFwaCBzaG93cyB0aGUgcHJvcG9ydGlvbiBvZiB0aGUgaW50ZXJwb2xhdGlvbiB2YWx1ZSBlYWNoIFN0YXRlIGhhcyBvdmVyIHRpbWUuCgoqTm90ZToqIFRoaXMgcGxvdCBpcyBpbnRlcmFjdGl2ZS4gRm9yIGVhc2UgY29tcGFyaXNvbiBiZXR3ZWVuIFN0YXRlcyB5b3UgY2FuOwoKLSAqT25lKiBjbGljayBvbiBhbnkgU3RhdGUgdG8gKnJlbW92ZSogaXQgZnJvbSB0aGUgcGxvdCAKLSAqVHdvKiBjbGlja3Mgb24gYW55IFN0YXRlIHRvICppc29sYXRlIGl0KiBmcm9tIHRoZSBwbG90IChvdGhlciBzdGF0ZXMgY2FuIHRoZW4gYmUgYWRkZWQgYnkganVzdCBjbGlja2luZyBvbiB0aGVtKS4KLSBUaGUgYm90dG9tIHBhbmVsIGFsbG93cyB5b3UgdG8gcmVkdWNlIHRoZSB0aW1lIGZyYW1lCgojIyMgRHluYW1pYyBhZ2dyZWdhdGVkIHBsb3QKCmBgYHtyIGR5bmFtaWNfYXJlYV9wbG90LCBldmFsID0gVCwgZWNobyA9IFQsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTB9Cgp0b3RhbF9maXRlZCA8LSBoaXN0b3JpY19zcHAgJT4lIAogIGdyb3VwX2J5KHllYXIscmVnaW9uKSAlPiUgCiAgc3VtbWFyaXNlKHRvdGFsX3ZhbHVlID0gc3VtKHZhbHVlLG5hLnJtPVQpLC5ncm91cHMgPSAiZHJvcCIpCgojIGdyb3VwIGJ5IHN0YXRlCnN0YXRlX2ZpdCA8LSBoaXN0b3JpY19zcHAgJT4lIAogIGdyb3VwX2J5KHN0YXRlLHllYXIscmVnaW9uKSAlPiUgCiAgc3VtbWFyaXNlKHN0YXRlX3ZhbHVlID0gc3VtKHZhbHVlLG5hLnJtPSBUKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lIAogIGxlZnRfam9pbih0b3RhbF9maXRlZCwKICAgICAgICAgICAgYnkgPSBjKCJ5ZWFyIiwicmVnaW9uIikpICU+JQogIG11dGF0ZShwZXJjZW50YWdlID0gc3RhdGVfdmFsdWUvdG90YWxfdmFsdWUqMTAwKQoKIyBQbG90IG1lCnAgPC0gZ2dwbG90KHN0YXRlX2ZpdCkgKwogIGdlb21fYXJlYSgKICAgIGFlcygKICAgICAgeCA9IHllYXIsCiAgICAgIHkgPSByb3VuZChwZXJjZW50YWdlKSwKICAgICAgZmlsbCA9IHN0YXRlCiAgICApCiAgKSArCiAgeWxhYigiUGVyY2VudGFnZSAoJSkiKSArCiAgIyB2aXJpZGlzOjpzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGUgPSBULCBhbHBoYSA9IDAuOCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHN0YXRlX3BhbGxldCkgKwogIE15RnVuY3Rpb25zOjpteV9nZ3RoZW1lX3AoKSArCiAgZmFjZXRfd3JhcCh+cmVnaW9uLCBuY29sID0gMSkgKwogIHRoZW1lX2RhcmsoKQoKZ2dwbG90bHkocCwKICAgICAgICAgZHluYW1pY1RpY2tzID0gVFJVRSkgJT4lIAogIGxheW91dChob3Zlcm1vZGUgPSAieCIpICU+JQogIHJhbmdlc2xpZGVyKCkKCmBgYAoKIyMgQXJlYSBwbG90IChydW5uaW5nIG1lYW4pCgpUaGlzIGdyYXBoIHNob3dzIHRoZSBwcm9wb3J0aW9uIG9mIGVhY2ggU3RhdGUgc21vb3RoZWQgb3ZlciBhICoxMCB5ZWFycyBydW5uaW5nIG1lYW4qKi4gSXQgYWxsb3dzIHRvIGJldHRlciBzZWUgaW5jcmVhc2luZyBhbmQgZGVjcmVhc2luZyB0cmVuZHMuCgojIyMgRHluYW1pYyBhZ2dyZWdhdGVkIHBsb3QKCipOb3RlOiogVGhpcyBwbG90IGlzIGFsc28gaW50ZXJhY3RpdmUgYW5kIHRodXMsIGZvbGxvd3MgdGhlIHNhbWUgb3B0aW9ucyBvZiB0aGUgcHJldmlvdXMgb25lLgoKYGBge3IgYXJlYV9wbG90LCBldmFsID0gVCwgZWNobyA9IFQsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTB9CgojIGdyb3VwIGJ5IHN0YXRlCnN0YXRlX2ZpdCA8LSBoaXN0b3JpY19zcHAgJT4lIAogIGdyb3VwX2J5KHN0YXRlLHllYXIscmVnaW9uLC5ncm91cHMgPSAiZHJvcCIpICU+JSAKICBzdW1tYXJpc2Uoc3RhdGVfdmFsdWUgPSBzdW0odmFsdWUsbmEucm09IFQpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgbGVmdF9qb2luKHRvdGFsX2ZpdGVkLAogICAgICAgICAgICBieSA9IGMoInllYXIiLCJyZWdpb24iKSkgJT4lCiAgbXV0YXRlKHBlcmNlbnRhZ2UgPSBzdGF0ZV92YWx1ZS90b3RhbF92YWx1ZSoxMDApICU+JSAKICBncm91cF9ieShzdGF0ZSxyZWdpb24pICU+JSAKICBtdXRhdGUoUk1lYW4gPSB6b286OnJvbGxtZWFuKHggPSBwZXJjZW50YWdlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IE5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm09VCkKICAgICkgJT4lICAKICBsZWZ0X2pvaW4oc3RhdGVfbGF0KQoKIyBQbG90IG1lCnAgPC0gZ2dwbG90KHN0YXRlX2ZpdCkgKwogIGdlb21fYXJlYSgKICAgIGFlcygKICAgICAgeCA9IHllYXIsCiAgICAgIHkgPSByb3VuZChSTWVhbiksCiAgICAgIGZpbGwgPSBzdGF0ZQogICAgICAjIGZpbGwgPSBvcmRlcgogICAgKQogICkgKwogIHlsYWIoIjEwIHlycyBydW5uaW5nIGF2ZXJhZ2UgKCUpIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKAogICAgIlN0YXRlIiwKICAgIHZhbHVlcyA9IHN0YXRlX3BhbGxldCwKICAgICMgbGFiZWxzID0gc3RhdGVfZml0ICU+JSBhcnJhbmdlKG9yZGVyKSAlPiUgIHB1bGwoc3RhdGUpICU+JSB1bmlxdWUoKQogICkgKwogIE15RnVuY3Rpb25zOjpteV9nZ3RoZW1lX3AoKSArCiAgZmFjZXRfd3JhcCh+cmVnaW9uLCBuY29sID0gMSkgKwogIHRoZW1lX2RhcmsoKQoKc3VwcHJlc3NXYXJuaW5ncygKZ2dwbG90bHkocCwKICAgICAgICAgZHluYW1pY1RpY2tzID0gVFJVRSkgJT4lIAogIGxheW91dChob3Zlcm1vZGUgPSAieCIpICU+JSAKICAjIGFkZF90cmFjZSgpICU+JSAKICByYW5nZXNsaWRlcigpCikKCmBgYAoKIyMjIEFnZ3JlZ2F0ZWQgUHJvcG9ydGlvbmFsIGNoYW5nZQoKYGBge3IgcGxvdF9hcmVhX2F2ZV9hZ2csIGV2YWwgPSBGLCBlY2hvID0gRiwgcmVzdWx0cz0naGlkZSd9Cgp0b3RhbF9maXRlZCA8LSBoaXN0b3JpY19zcHAgJT4lIAogIGdyb3VwX2J5KHllYXIscmVnaW9uLHNwYXRpYWwpICU+JSAKICBzdW1tYXJpc2UodG90YWxfdmFsdWUgPSBzdW0odmFsdWUsbmEucm09VCksLmdyb3VwcyA9ICJkcm9wIikKCgojIGdyb3VwIGJ5IHN0YXRlCnN0YXRlX2ZpdCA8LSBoaXN0b3JpY19zcHAgJT4lIAogIGdyb3VwX2J5KHN0YXRlLHllYXIscmVnaW9uLHNwYXRpYWwpICU+JSAKICBzdW1tYXJpc2Uoc3RhdGVfdmFsdWUgPSBzdW0odmFsdWUsbmEucm09IFQpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgbGVmdF9qb2luKHRvdGFsX2ZpdGVkLAogICAgICAgICAgICBieSA9IGMoInllYXIiLCJyZWdpb24iLCJzcGF0aWFsIikpICU+JQogIG11dGF0ZShwZXJjZW50YWdlID0gc3RhdGVfdmFsdWUvdG90YWxfdmFsdWUqMTAwKSAlPiUgCiAgZ3JvdXBfYnkoc3RhdGUscmVnaW9uLHNwYXRpYWwpICU+JSAKICBtdXRhdGUoUk1lYW4gPSB6b286OnJvbGxtZWFuKHggPSBwZXJjZW50YWdlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IE5BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm09VCkKICAgICkgJT4lIAogICNPbmx5IHNob3cgcmVzdWx0cyBmb3Igc3ByaW5nCiAgZmlsdGVyKHN0cl9kZXRlY3QocmVnaW9uLCJTcHJpbmciKSwKICAgICAgICAgIWlzLm5hKFJNZWFuKSAjIFJlbW92ZSBOQXMgZnJvbSByb2xsbWVhbgogICAgICAgICApICU+JSAgCiAgbGVmdF9qb2luKHN0YXRlX2xhdCkgJT4lIAogIG11dGF0ZSgKICAgICAgICAgc3BhdGlhbCA9IGlmZWxzZShzcGF0aWFsID09ICJmcCIsIkZpc2hpbmcgcG9ydHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShzcGF0aWFsID09ICJzdyIsIlN0YXRlIFdhdGVycyIsIkRpZmZlcmVuY2UiKQogICAgICAgICApCiAgKQoKCiMgUGxvdCBtZQphZ2dfYXJlYSA8LSBnZ3Bsb3Qoc3RhdGVfZml0KSArCiAgZ2VvbV9hcmVhKAogICAgYWVzKAogICAgICB4ID0geWVhciwKICAgICAgeSA9IHJvdW5kKFJNZWFuKSwKICAgICAgZmlsbCA9IG9yZGVyCiAgICAgICMgZmlsbCA9IHN0YXRlCiAgICApCiAgKSArCiAgYW5ub3RhdGUoZ2VvbT0gInJlY3QiLAogICAgICAgICAgIHhtaW4gPSAxOTgwLCB4bWF4ID0gMjAwMSwgCiAgICAgICAgICAgeW1pbiA9IDAsIHltYXggPSAxMDAsCiAgICAgICAgICAgIGZpbGwgPSAiZ3JheTkwIiwKICAgICAgICAgICBjb2xvdXIgPSBOQSwKICAgICAgICAgICBhbHBoYSA9IDAuNSkgKwogIHlsYWIoIlByb3BvdGlvbiAoMTAgeXJzIHJ1bm5pbmcgYXZlcmFnZSkiKSArCiAgIyB2aXJpZGlzOjpzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGUgPSBULCBhbHBoYSA9IDAuOCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKAogICAgIlN0YXRlXG4oTGF0aXR1ZGluYWwgb3JkZXIpIiwKICAgIHZhbHVlcyA9IHN0YXRlX3BhbGxldCwKICAgIGxhYmVscyA9IHN0YXRlX2ZpdCAlPiUgYXJyYW5nZShvcmRlcikgJT4lICBwdWxsKHN0YXRlKSAlPiUgdW5pcXVlKCkKICApICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDE5NzksMjAxNSw5KSxsaW1pdHMgPSBjKDE5NzksMjAxNSkpKwogIHhsYWIoIlllYXIiKSArCiAgbXlfZ2d0aGVtZV9wKGxlZ19wb3MgPSAicmlnaHQiLCBoanVzdCA9IDEsYXhfdHhfcyA9IDEwLGxlZ190eF9zID0gMTAsIGxlZ190bF9zID0gMTIsYXhfdGxfcyA9IDEyKSArCiAgdGhlbWUobGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMSwibGluZSIpLAogICAgICAgIGxlZ2VuZC50aXRsZS5hbGlnbj0wLjUpICsKICBmYWNldF93cmFwKH5zcGF0aWFsKSAKCgogICAgZ2dzYXZlKGZpbGVuYW1lID0gImFyZWFfcGxvdF9hdmdfYWdnX3NwdGwuanBnIiwKICAgICAgICAgcGxvdCA9IGFnZ19hcmVhLAogICAgICAgICBwYXRoID0gbXlfcGF0aCgiUiIsIkZpZ3VyZXMiKSwKICAgICAgICAgd2lkdGggPSA4LAogICAgICAgICBoZWlnaHQgPSA2CiAgICAgICAgICkKCgpgYGAKCiMjIyBQYXBlciBmaWd1cmU6IFBlciBTcGVjaWVzIFByb3BvcnRpb25hbCBjaGFuZ2UKCmBgYHtyIHBhcGVyX3Bsb3RfYXJlYV9hdmVfc3BwLCBldmFsID0gRiwgZWNobyA9IEYsIHJlc3VsdHM9J2hpZGUnfQoKdG90YWxfZml0ZWQgPC0gaGlzdG9yaWNfc3BwICU+JSAKICBncm91cF9ieSh5ZWFyLHJlZ2lvbixzcHAsc3BhdGlhbCkgJT4lIAogIHN1bW1hcmlzZSh0b3RhbF92YWx1ZSA9IHN1bSh2YWx1ZSxuYS5ybT1UKSwuZ3JvdXBzID0gImRyb3AiKQoKCiMgZ3JvdXAgYnkgc3RhdGUKc3RhdGVfZml0IDwtIGhpc3RvcmljX3NwcCAlPiUgCiAgZ3JvdXBfYnkoc3RhdGUseWVhcixsYWJlbCxyZWdpb24sc3BwLHNwYXRpYWwpICU+JSAKICBzdW1tYXJpc2Uoc3RhdGVfdmFsdWUgPSBzdW0odmFsdWUsbmEucm09IFQpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgbGVmdF9qb2luKHRvdGFsX2ZpdGVkLAogICAgICAgICAgICBieSA9IGMoInllYXIiLCJyZWdpb24iLCJzcHAiLCJzcGF0aWFsIikpICU+JQogIG11dGF0ZShwZXJjZW50YWdlID0gc3RhdGVfdmFsdWUvdG90YWxfdmFsdWUqMTAwKSAlPiUgCiAgZ3JvdXBfYnkoc3RhdGUscmVnaW9uLHNwcCxzcGF0aWFsKSAlPiUgCiAgbXV0YXRlKFJNZWFuID0gem9vOjpyb2xsbWVhbih4ID0gcGVyY2VudGFnZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAxMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBOQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtPVQpCiAgICApICU+JSAKICAjT25seSBzaG93IHJlc3VsdHMgZm9yIHNwcmluZwogIGZpbHRlcihzdHJfZGV0ZWN0KHJlZ2lvbiwiU3ByaW5nIiksCiAgICAgICAgICFpcy5uYShSTWVhbikgIyBSZW1vdmUgTkFzIGZyb20gcm9sbG1lYW4KICAgICAgICAgKSAlPiUgIAogIGxlZnRfam9pbihzdGF0ZV9sYXQpICU+JSAKICBtdXRhdGUoCiAgICAgICAgIHNwYXRpYWwgPSBpZmVsc2Uoc3BhdGlhbCA9PSAiZnAiLCJGaXNoaW5nIHBvcnRzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uoc3BhdGlhbCA9PSAic3ciLCJTdGF0ZSB3YXRlcnMiLCJEaWZmZXJlbmNlIikKICAgICAgICAgKQogICkKCgojIFNoYWRlZCBwZXJpb2QgCmhpc3RvcmljX3BlcmlvZHMgPC0gaGlzdG9yaWNfc3BwICU+JSAKICBmaWx0ZXIobGFiZWwgPT0gIlJlZmVyZW5jZSIpICU+JSAKICBncm91cF9ieShzcHAsbGFiZWwseWVhcikgJT4lIAogIHN1bW1hcmlzZShuID0gbigpLW4oKSsxMDApICU+JSAKICBtdXRhdGUocGVyaW9kID0gIlJlZmVyZW5jZSBwZXJpb2QiKQoKCiMgUGxvdCBtZQpzc3BfYXJlYSA8LQogIGdncGxvdChzdGF0ZV9maXQpICsKICBnZW9tX2FyZWEoCiAgICBhZXMoCiAgICAgIHggPSB5ZWFyLAogICAgICB5ID0gcm91bmQoUk1lYW4pLAogICAgICBmaWxsID0gb3JkZXIKICAgICAgIyBmaWxsID0gc3RhdGUKICAgICkKICApICsKICBnZW9tX2FyZWEoZGF0YSA9IGhpc3RvcmljX3BlcmlvZHMsCiAgICAgICAgICAgICBhZXMoCiAgICAgICAgICAgICAgIHggPSB5ZWFyLAogICAgICAgICAgICAgICB5ID0gbiwKICAgICAgICAgICAgICAgY29sb3IgPSBwZXJpb2QKICAgICAgICAgICAgICksCiAgICAgICAgICAgICAjIGZpbGwgPSAiZ3JheTkwIiwKICAgICAgICAgICAgIGFscGhhID0gMC4zLAogICAgICAgICAgICBzdGF0ID0gImlkZW50aXR5IgogICAgICAgICAgICAgKSArCiAgIyBhbm5vdGF0ZShnZW9tPSAicmVjdCIsCiAgIyAgICAgICAgICB4bWluID0gMTk4MCwgeG1heCA9IDIwMDEsIAogICMgICAgICAgICAgeW1pbiA9IDAsIHltYXggPSAxMDAsCiAgIyAgICAgICAgICAgZmlsbCA9ICJncmF5OTAiLAogICMgICAgICAgICAgY29sb3VyID0gTkEsCiAgIyAgICAgICAgICBhbHBoYSA9IDAuNSkgKwogIHlsYWIoIlByb3BvdGlvbiAoMTAgeXJzIHJ1bm5pbmcgYXZlcmFnZSkiKSArCiAgIyB2aXJpZGlzOjpzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGUgPSBULCBhbHBoYSA9IDAuOCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKAogICAgIlN0YXRlXG4oTGF0aXR1ZGluYWwgb3JkZXIpIiwKICAgIHZhbHVlcyA9IHN0YXRlX3BhbGxldCwKICAgIGxhYmVscyA9IHN0YXRlX2ZpdCAlPiUgYXJyYW5nZShvcmRlcikgJT4lICBwdWxsKHN0YXRlKSAlPiUgdW5pcXVlKCkKICApICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCgiIix2YWx1ZXMgPSAiZ3JleTkwIgogICkgKwogIGZhY2V0X2dyaWQoc3BwfnNwYXRpYWwpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDE5NzksMjAxNSw5KSxsaW1pdHMgPSBjKDE5NzksMjAxNSkpKwogIHhsYWIoIlllYXIiKSArCiAgbXlfZ2d0aGVtZV9wKGxlZ19wb3MgPSAicmlnaHQiLCBoanVzdCA9IDAuOSxheF90eF9zID0gMTQsbGVnX3R4X3MgPSAxNiwgbGVnX3RsX3MgPSAxOCxheF90bF9zID0gMTgsZmFjZXRfdHhfcyA9IDE2KSArCiAgdGhlbWUobGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMSwibGluZSIpLAogICAgICAgIGxlZ2VuZC50aXRsZS5hbGlnbj0wLjUpCgoKICBnZ3NhdmUoZmlsZW5hbWUgPSAiYXJlYV9wbG90X2F2Z19zcHBfc3B0bC5qcGciLAogICAgICAgICBwbG90ID0gc3NwX2FyZWEsCiAgICAgICAgIHBhdGggPSBteV9wYXRoKCJSIiwiRmlndXJlcyIpLAogICAgICAgICB3aWR0aCA9IDE0LAogICAgICAgICBoZWlnaHQgPSA4CiAgKQoKCmBgYAo8IS0tICFbUHJvcG9ydGlvbiBjaGFuZ2UgYWdncmVnYXRlZCBhbGwgc3BlY2llcyBtYXAgZm9yIHBhcGVyXSgvVm9sdW1lcy9FbnRlcnByaXNlL0RhdGEvQWNyb3NzQm91bmRhcmllcy9SZXN1bHRzL0ZpZ3VyZXMvYXJlYV9wbG90X2F2Z19zcHBfc3B0bC5qcGcpIC0tPgoKIyBPbGQgY29kZQoKIyMgRmlzaGluZyBwb3J0cyBXUEkKCldlIHVzZWQgW0dsb2JhbCBGaXNoaW5nIFdhdGNoXShodHRwczovL2dsb2JhbGZpc2hpbmd3YXRjaC5vcmcvZGF0YXNldHMtYW5kLWNvZGUtYW5jaG9yYWdlcy8pJ3MgZGF0YWJhc2Ugb24gCkFuY2hvcmFnZXMsIFBvcnRzIGFuZCBWb3lhZ2VzLgoKKlRoZSBHbG9iYWwgRmlzaGluZyBXYXRjaCBhbmNob3JhZ2VzIGRhdGFzZXQgaXMgYSBnbG9iYWwgZGF0YWJhc2Ugb2YgYW5jaG9yYWdlIGxvY2F0aW9ucyB3aGVyZSB2ZXNzZWxzIGNvbmdyZWdhdGUuIFRoZSBkYXRhc2V0IGNvbnRhaW5zIG92ZXIgMTYwLDAwMCBpbmRpdmlkdWFsIGFuY2hvcmFnZSBsb2NhdGlvbnMsIHdoaWNoIGFyZSBmdXJ0aGVyIGdyb3VwZWQgaW50byBuZWFybHkgMzIsMDAwIHBvcnRzIHdoZW4gYXBwbGljYWJsZS4qCgoKYGBge3IgcG9ydHNfc2YsIGV2YWwgPSBULCBlY2hvID0gVH0KCiMgR2V0IEdsb2JhbCBGaXNoaWcgV2F0Y2ggZGF0YQpnZndfZGF0YSA8LSBteV9wYXRoKCJEIiwiU3BhdGlhbCIsbmFtZSA9ICJnZndfcG9ydGRhdGEuY3N2IiwgcmVhZCA9IFQpICU+JSAKICBmaWx0ZXIoaXNvMyA9PSAiVVNBIikgCgojIFZpc3VhbGl6ZSBkYXRhIChvLmshKQojIGdncGxvdChnZndfZGF0YSkgKwojICAgZ2VvbV9wb2ludCgKIyAgICAgYWVzKAojICAgICB4ID0gbG9uLAojICAgICB5ID0gbGF0CiMgICApCiMgICApCgojIENvbnZlcnQgZGF0YSB0byBzZiBmb3IgbWVyZ2lnCmdmd19zZiA8LSBzdF9hc19zZihnZndfZGF0YSwKICAgICAgICAgICAgIGNvb3JkcyA9IGMoImxvbiIsICJsYXQiKSwKICAgICAgICAgICAgIGNycyA9IDQzMjYpCgojIE1lcmdlIGRhdGEgd2l0aCBzdGF0ZSB3YXRlcnMgdG8sbG9jYXRlIHBvcnRzIApwb3J0X3NmIDwtIHN0X2pvaW4oZ2Z3X3NmLHN0YXRlX3NmKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShqdXJpc2RpY3RpKSkgIyByZW1vdmUgcG9pbnRzIG91dHNpZGUgc3RhdCB3YXRlcnMKCmdncGxvdChwb3J0X3NmKSAgKwogIGdlb21fc2YoYWVzKGNvbG9yID0gZGlzdGFuY2VfZnJvbV9zaG9yZV9tKSkgKwogIHRoZW1lX2RhcmsoKQoKYGBgClNvLi4uTG9va3MgbGlrZSBzb21lIHBvcnRzIGFyZSAiZmFyIGZyb20gc2hvcmUiIHdoaWNoIEkgZG9uJ3QgcmVhbGx5IGtub3cgd2hhdCBpdCBtZWFucy4gRm9yIG5vdywgSSBhbSBvbmx5IHNlbGVjdGluZyB0aG9zZSBwb3J0cyB0aGF0IGFyIDAgbWV0ZXIgZnJvbSBzaG9yZS4gCgoKYGBge3IgcG9ydHNfaW5zaG9yZSwgZXZhbCA9IFQsIGVjaG8gPSBGfQoKIyBHZXQgbnVtYmVyIG9mIHBvcnRzIHBlciBzdGF0ZQpwb3J0c19uX2RhdGEgPC0gcG9ydF9zZiAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpICU+JSAKICAgIGZpbHRlcihkaXN0YW5jZV9mcm9tX3Nob3JlX20gPT0gMCkgJT4lIAogICAgZ3JvdXBfYnkoc3RhdGUpICU+JSAKICAgIHN1bW1hcmlzZShuX3BvcnRzID0gbigpKSAKCiMgcGxvdCBpdApncmlkRXh0cmE6OmdyaWQuYXJyYW5nZSgKICBwb3J0X3NmICU+JSAKICAgIGZpbHRlcihkaXN0YW5jZV9mcm9tX3Nob3JlX20gPT0gMCkgJT4lIAogICAgZ2dwbG90KCkgICsKICAgIGdlb21fc2YoYWVzKGNvbG9yID0ganVyaXNkaWN0aSkpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBzdGF0ZV9wYWxsZXQpICsKICAgIHRoZW1lX2RhcmsoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiIiksCiAgdGFibGVHcm9iKHBvcnRzX25fZGF0YSksCiAgbmNvbCA9IDIKKQoKCmBgYAoKClRoZXJlIGFyZSBzdGlsbCB0b28gbWFueSBwb3J0cyBpbiBlYWNoIHN0YXRlICg/KS4gU3BlY2lhbGx5IE5ldyBKZXJzZXkhIE9uZSBhcHByb2FjaCBpcyB0byB1c2UgTk9BQSdzIGxhbmRpbmctcGVyLXBvcnQgZGF0YSB0byBmaWx0ZXIgb3V0Li4uIAoKIyMjIyMjIDQuMiBXb3JsZCBQb3J0IEluZGV4IAoKSW4gdGhpcyBhcHByb2FjaCB3ZSBvbmx5IHVzZSB0aGUgcG9ydHMgY2F0ZWdvcml6ZWQgd2l0aGluIHRoZSBbV1BJXShodHRwczovL21zaS5uZ2EubWlsL05HQVBvcnRhbC9NU0kucG9ydGFsP19uZnBiPXRydWUmX3BhZ2VMYWJlbD1tc2lfcG9ydGFsX3BhZ2VfNjImcHViQ29kZT0wMDE1KSBhbmQgd2l0aCBgZGlzdGFuY2VfZnJvbV9zaG9yZV9tID09IDBgICBhbmQgYGF0X2RvY2sgPT0gVFJVRWAuCgotIGBhdF9kb2NrYCA9PSBBbmNob3JhZ2VzIHdpdGhpbiBhIDQ1MCBtZXRlciBidWZmZXIgYXJvdW5kIGEgY29tYmluZWQgbGFuZCBzaGFwZSBmaWxlIGFyZSBjb25zaWRlcmVkIGF0IGRvY2suIAoKYGBge3Igd3BpX2FwcHJvYWNoLCBldmFsID0gVCwgZWNobyA9IEZ9CgpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZSgKICBwb3J0X3NmICU+JSAKICAgIGZpbHRlcihkaXN0YW5jZV9mcm9tX3Nob3JlX20gPT0gMCwKICAgICAgICAgICBsYWJlbF9zb3VyY2UgJWluJSBjKCJXUElfcG9ydHMiKSwKICAgICAgICAgICBhdF9kb2NrID09IFRSVUUpICU+JSAKICAgIGdncGxvdCgpICArCiAgICBnZW9tX3NmKGFlcyhjb2xvciA9IGp1cmlzZGljdGkpKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gc3RhdGVfcGFsbGV0KSArCiAgICB0aGVtZV9kYXJrKCksCiAgcG9ydF9zZiAlPiUgCiAgICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogICAgZmlsdGVyKGRpc3RhbmNlX2Zyb21fc2hvcmVfbSA9PSAwLAogICAgICAgICAgIGxhYmVsX3NvdXJjZSAlaW4lIGMoIldQSV9wb3J0cyIpLAogICAgICAgICAgIGF0X2RvY2sgPT0gVFJVRSkgJT4lIAogICAgZ3JvdXBfYnkoc3RhdGUpICU+JSAKICAgIHN1bW1hcmlzZShuX3BvcnRzID0gbigpKSAlPiUgCiAgICB0YWJsZUdyb2IoKSwKICBuY29sID0gMgopCgoKYGBgCgojIyBIaXN0b3JpYyBxdW90YSBWcyBkaXN0cmlidXRpb25zCgpUaGlzIHNlY3Rpb24gb2YgdGhlIHJlc3VsdHMgZXhwbG9yZXMgdGhlIGRpZmZlcmVuY2VzIGJldHdlZW4gdGhlIGhpc3RvcmljIGRpc3RyaWJ1dGlvbiBvZiB0ZSBzdG9jayBhbmQgdGhlIGhpc3RvcmljIHF1b3RhIGFsbG9jYXRpb24uIFdlIGNvbGxlY3RlZCB0aGUgcHJvcG9ydGlvbiBvZiB0aGUgdG90YWwgcXVvdGEgdGhhdCBlYWNoIFN0YXRlIGdldHMgZm9yIGVhY2ggc3BlY2llcy4KClJpZ2h0IG5vdyB0aGUgYW5hbHlzaXMgb25seSBjb3ZlcnMgYmxhY2sgc2VhIGJhc3MsIHN1bW1lciBmbG91bmRlciBhbmQgc2N1cC4gQnV0IHdlIGNhbiBnbyBzcGVjZWlzIGJ5IHNwZWNpZXMgdG8gc2VlIHdoaWNoIG9uZXMgaGF2ZSB0aGVpciBxdW90YSBhbGxvY2F0ZWQgYnkgc3RhdGUgdG8gaW5jbHVkZSB0aGVtIGluIHRoZSBhbmFseXNpcy4KCi0gW0JsYWNrIFNlYSBCYXNzOyAqQ2VudHJvcHJpc3RpcyBzdHJpYXRhKl0oaHR0cHM6Ly93d3cubWFmbWMub3JnL25ld3NmZWVkLzIwMjEvYXNtZmMtYW5kLW1hZm1jLWFwcHJvdmUtYnNiLWNvbW1lcmNpYWwtYWxsb2NhdGlvbi1jaGFuZ2VzKQoKKipOb3RlOioqIFdlIGFyZSB1c2luZyB0aGUgbmV3IGFsbG9jYXRpb25zIGJhc2VkIG9uIHRoZSBzdG9jaydzIG1vc3QgcmVjZW50IGJpb21hc3MgZGlzdHJpYnV0aW9uKiAKCi0gW1N1bW1lciBmbG91bmRlcl0oaHR0cDovL3d3dy5hc21mYy5vcmcvdXBsb2Fkcy9maWxlLzVmOWFmODJhMjAxOVN1bW1lckZsb3VuZGVyRk1QX1Jldmlldy5wZGYpCgotIFtTY3VwXShodHRwOi8vd3d3LmFzbWZjLm9yZy91cGxvYWRzL2ZpbGUvNWY5OWQwMTEyMDE5X1NjdXBfRk1QX1Jldmlld19hcHByb3ZlZC5wZGYpIFN1bW1lciBwZXJpb2QKCkZvciBTdGF0ZS1sZXZlbCBtYW5hZ2VkIHNwZWNpZXMgc2VlIHRoZSBbQXRsYW50aWMgU3RhdGVzIE1hcmluZSBGaXNoZXJpZXMgQ29taXNzaW9uXShodHRwOi8vd3d3LmFzbWZjLm9yZy9maXNoZXJpZXMtbWFuYWdlbWVudC9wcm9ncmFtLW92ZXJ2aWV3KSB3ZWJzaXRlIGFuZCBnbyBzcGVjaWVzLWJ5LXNwZWNpZXMuCgoKYGBge3Igc3RhdGVfcXVvdGFfdGJsLGV2YWw9IFQsIGVjaG8gPSBUfQoKcXVvdGFfYWxsb2NhdGlvbiA8LSBzdGF0ZV9sYXQgJT4lIAogIG11dGF0ZSgKICAgICJDZW50cm9wcmlzdGlzIHN0cmlhdGEiID0gYygKICAgICAgMC4wMDQwLCAjTUUKICAgICAgMC4wMDQwLCAjTkgKICAgICAgMC4xNTY0LCAjTUEKICAgICAgMC4xMzIzLCAjUkkKICAgICAgMC4wMzY3LCAjQ1QKICAgICAgMC4wODU3LCAjTlkKICAgICAgMC4yMDEwLCAjTkoKICAgICAgMC4wNDExLCAjREUKICAgICAgMC4wODg4LCAjTUQKICAgICAgMC4xNjE0LCAjVkEKICAgICAgMC4wODg4ICNOQwogICAgKSwKICAgICJQYXJhbGljaHRoeXMgZGVudGF0dXMiID0gYygKICAgICAgMC4wMDA0NzU2LCAjTUUgCiAgICAgIDAuMDAwMDA0NiwgI05IIAogICAgICAwLjA2ODIwNDYsICNNQSAKICAgICAgMC4xNTY4Mjk4LCAjUkkgCiAgICAgIDAuMDIyNTcwOCwgI0NUIAogICAgICAwLjA3NjQ2OTksICNOWSAKICAgICAgMC4xNjcyNDk5LCAjTkogCiAgICAgIDAuMDAwMTc3OSwgI0RFIAogICAgICAwLjAyMDM5MTAsICNNRAogICAgICAwLjIxMzE2NzYsICNWQQogICAgICAwLjI3NDQ1ODQgI05DCiAgICApLAogICAgIlN0ZW5vdG9tdXMgY2hyeXNvcHMiID0gYygKICAgICAgMC4wMDEyMTAxLCAjTUUKICAgICAgMC4wMDAwMDAwLCAjSE4KICAgICAgMC4yMTU4NzI5LCAjTUEKICAgICAgMC41NjE5NDU2LCAjUkkKICAgICAgMC4wMzE1Mzk5LCAjQ1QKICAgICAgMC4xNTgyNDY2LCAjTlkKICAgICAgMC4wMjkxNjY3LCAjTkoKICAgICAgMC4wMDAwMDAwLCAjREUKICAgICAgMC4wMDAxMTkwLCAjTUQKICAgICAgMC4wMDE2NTAyLCAjVkEKICAgICAgMC4wMDAyNDkwICNOQwogICAgKQogICkgJT4lIAogIGdhdGhlcigic3BwIiwicXVvdGEiLDQ6NikKCiMgRG91YmxlIGNoZWNrIHRoZXkgYWxsIGFkZCB0byAxLi4uCnF1b3RhX2FsbG9jYXRpb24gJT4lIAogIGdyb3VwX2J5KHNwcCkgJT4lIAogIHN1bW1hcmlzZV9hdCh2YXJzKHF1b3RhKSxzdW0pCgoKcXVvdGFfYWxsb2NhdGlvbiAlPiUgCiAgYXJyYW5nZShvcmRlcikgJT4lIAogIHNlbGVjdCgtb3JkZXIpICU+JSAKICBzcHJlYWQoc3BwLHF1b3RhKSAlPiUgCiAga2FibGUoKQpgYGAKCgojIyMgR2V0IGRhdGEgcmVhZHkKCmBgYHtyfQoKdG90YWxfZml0ZWQgPC0gaGlzdG9yaWNfc3BwICU+JSAKICBncm91cF9ieSh5ZWFyLHJlZ2lvbixzcHApICU+JSAKICBzdW1tYXJpc2UodG90YWxfdmFsdWUgPSBzdW0odmFsdWUsbmEucm09VCksLmdyb3VwcyA9ICJkcm9wIikKCiMgZ3JvdXAgYnkgc3RhdGUKc3RhdGVfZml0IDwtIGhpc3RvcmljX3NwcCAlPiUgCiAgZ3JvdXBfYnkoc3RhdGUseWVhcixyZWdpb24sc3BwKSAlPiUgCiAgc3VtbWFyaXNlKHN0YXRlX3ZhbHVlID0gc3VtKHZhbHVlLG5hLnJtPSBUKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lIAogIGxlZnRfam9pbih0b3RhbF9maXRlZCwKICAgICAgICAgICAgYnkgPSBjKCJ5ZWFyIiwicmVnaW9uIiwic3BwIikpICU+JQogIG11dGF0ZShwZXJjZW50YWdlID0gc3RhdGVfdmFsdWUvdG90YWxfdmFsdWUqMTAwKSAlPiUgCiAgI09ubHkgc2hvdyByZXN1bHRzIGZvciBzcHJpbmcKICBmaWx0ZXIoc3RyX2RldGVjdChyZWdpb24sIlNwcmluZyIpKQoKcXVvdGFfZGYgPC0gcXVvdGFfYWxsb2NhdGlvbiAlPiUgCiAgbGVmdF9qb2luKGhpc3RvcmljX3NwcCkgJT4lIAogIGdyb3VwX2J5KHN0YXRlLGFicmV2LHllYXIscmVnaW9uLHNwcCxxdW90YSkgJT4lIAogIHN1bW1hcmlzZShzdGF0ZV92YWx1ZSA9IHN1bSh2YWx1ZSxuYS5ybT0gVCksIC5ncm91cHMgPSAiZHJvcCIpICU+JSAKICBsZWZ0X2pvaW4odG90YWxfZml0ZWQsCiAgICAgICAgICAgIGJ5ID0gYygieWVhciIsInJlZ2lvbiIsInNwcCIpKSAlPiUKICBtdXRhdGUoRGlzdHJpYnV0aW9uID0gc3RhdGVfdmFsdWUvdG90YWxfdmFsdWUqMTAwLAogICAgICAgICBIaXN0b3JpYyA9IHF1b3RhKjEwMCkgJT4lIAogIGdyb3VwX2J5KHN0YXRlLHF1b3RhLHNwcCkgJT4lIAogIG11dGF0ZShSTWVhbiA9IHpvbzo6cm9sbG1lYW4oeCA9IERpc3RyaWJ1dGlvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAxMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBOQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtPVQpCiAgICApICU+JSAKICAjT25seSBzaG93IHJlc3VsdHMgZm9yIHNwcmluZwogIGZpbHRlcihzdHJfZGV0ZWN0KHJlZ2lvbiwiU3ByaW5nIiksCiAgICAgICAgICFpcy5uYShSTWVhbikgIyBSZW1vdmUgTkFzIGZyb20gcm9sbG1lYW4KICAgICAgICAgKSAlPiUgIAogIGxlZnRfam9pbihzdGF0ZV9sYXQpICU+JSAKICBmaWx0ZXIoCiAgICAjIHNwcCA9PSJDZW50cm9wcmlzdGlzIHN0cmlhdGEiCiAgICBzcHAgJWluJSBxdW90YV9hbGxvY2F0aW9uJHNwcAogICkKCmhlYWQocXVvdGFfZGYpICU+JSAKICBrYWJsZSgpCmBgYAoKIyMjIEV4cGxvcmluZyBkaWZmZXJlbnQgd2F5cyB0byBzaG93IHRoZSByZXN1bHRzCgojIyMjIERpZmZlcmVuY2UgbGluZSBwbG90CgpUaGlzIHZlcnNpb24gc2hvd3MgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgSGlzdG9yaWMgcXVvdGEgYWxsb2NhdGlvbiBhbmQgdGhlIGRpc3RyaWJ1dGlvbiBwcm9wb3J0aW9uIG9mIHRoZSBzdG9jazoKCi0gZGlmZiA8IDAgPSB0aGUgZGlzdHJpYnV0aW9uIHByb3BvcnRpb24gaXMgKmxhcmdlciogdGhhbiB0aGUgYWxsb2NhdGVkIHF1b3RhCi0gZGlmZiA+IDAgPSB0aGUgZGlzdHJpYnV0aW9uIHByb3BvcnRpb24gaXMgKnNtYWxsZXIqIHRoYW4gdGhlIGFsbG9jYXRlZCBxdW90YSAKCmBgYHtyfQojIE9wdGlvbiBvbmUKCnF1b3RhX2RmICU+JQogIG11dGF0ZShkaWZmID0gSGlzdG9yaWMtIERpc3RyaWJ1dGlvbiwKICAgICAgICAgZGlmZl9ybWVhbiA9IFJNZWFuLSBEaXN0cmlidXRpb24pICU+JSAKICBnYXRoZXIoInR5cGUiLCJ2YWx1ZSIsZGlmZjpkaWZmX3JtZWFuKSAlPiUgCiAgIyBWaWV3KCkKICBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKAogICAgYWVzKAogICAgICB4ID0geWVhciwKICAgICAgeSA9IHZhbHVlLAogICAgICBjb2xvciA9IG9yZGVyCiAgICApCiAgKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKCJTdGF0ZSIsCiAgICB2YWx1ZXMgPSBzdGF0ZV9wYWxsZXQsCiAgICBsYWJlbHMgPSBxdW90YV9kZiAlPiUgYXJyYW5nZShvcmRlcikgJT4lICBwdWxsKHN0YXRlKSAlPiUgdW5pcXVlKCkKICAgICkgKwogIGZhY2V0X2dyaWQodHlwZX5zcHAsIAogICAgICAgICAgICAgc2NhbGVzID0gImZyZWUiKSArCiAgdGhlbWVfZGFyaygpCgpgYGAKIyMjIyBMaW5ldHlwZSBwbG90CgpIZXJlLCB3ZSBwbG90IHRoZSBkaXN0cmlidXRpb25hbCBxdW90YSAoc29saWQgbGluZXMpIHdpdGggZWFjaCBTdGF0ZSdzIGFsbG9jYXRpb24gd2l0aCBkYXNoZWQgKC0tLS0pIGxpbmVzCgpgYGB7cn0KIyBPcHRpb24gb25lCgpxdW90YV9kZiAlPiUgCiAgZ2F0aGVyKCJsZXZlbCIsInF1b3RhIixEaXN0cmlidXRpb246Uk1lYW4pICU+JSAKICAjIG11dGF0ZShkaWZmID0gcXVvdGFfcGVyLSBwZXJjZW50YWdlKSAlPiUgCiAgIyBWaWV3KCkKICBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKAogICAgYWVzKAogICAgICB4ID0geWVhciwKICAgICAgeSA9IHF1b3RhLAogICAgICBjb2xvciA9IG9yZGVyCiAgICApCiAgKSArCiAgbGFicyh4ID0gIlllYXIiLHkgPSAiUXVvdGEgKCUpIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKCJTdGF0ZSIsCiAgICB2YWx1ZXMgPSBzdGF0ZV9wYWxsZXQsCiAgICBsYWJlbHMgPSBxdW90YV9kZiAlPiUgYXJyYW5nZShvcmRlcikgJT4lICBwdWxsKHN0YXRlKSAlPiUgdW5pcXVlKCkKICAgICkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgiU3RhdGUiLAogICAgdmFsdWVzID0gc3RhdGVfcGFsbGV0LAogICAgbGFiZWxzID0gcXVvdGFfZGYgJT4lIGFycmFuZ2Uob3JkZXIpICU+JSAgcHVsbChzdGF0ZSkgJT4lIHVuaXF1ZSgpCiAgICApICsKICBzY2FsZV9saW5ldHlwZSgiUXVvdGEiKSArCiAgZmFjZXRfZ3JpZChzcHAgfiBsZXZlbCkrCiAgdGhlbWVfZGFyaygpCgpgYGAKIyMjIyBFZmZpY2llbmN5IGluZGV4CgpUaGUgaWRlYSBoZXJlIGlzIGNyZWF0ZSBhbmQgKmVmZmljaWVuY3kgaW5kZXgqIChEYW5nZXIhKSB0aGF0IGNvbXB1dGVzIHRoZSBhbGlnbm1lbnQgYmV0d2VlbiB0aGUgZGlzdHJpYnV0aW9uIGFuZCB0aGUgYWN0dWFsIGFsbG9jYXRpb24uIFRoZSBpbmRleCBpcyBzaW1wbHk7CgokJGVpID0gXGZyYWN7SGlzdG9yaWNRdW90YX17RGlzdHJpYnV0aW9uUHJvcG9ydGlvbn0kJCAKU28sIGluIGNhc2VzIHdoZXJlICplaSogPSAxLCB0aGUgcXVvdGEgaXMgYWxpZ25lZCB3aXRoIHRoZSBkaXN0cmlidXRpb247IHdoZW4gKmVpKiA+IDEgdGhlbiB0aGUgaGlzdG9yaWMgcXVvdGEgaXMgbW9yZSB0aGFuIHRoZSBzdG9jaydzIFN0YXRlJ3MgZGlzdHJpYnV0aW9uLCBjb250cmFyaWx5LCAqZWkqIDwgMSBtZWFucyB0aGF0IHRoZSBoaXN0b3JpYyBxdW90YSBpcyBsZXNzIHRoYW4gd2hhdCB0aGUgU3RhdGUgY3VycmVudGx5IGhhcy4KCgoqKk5vdGU6KiogCi0gVGhlcmUgYXJlIHNvbWUgY3Jhenp5IG91dGxpZXJzIHRoYXQgaGF2ZSBiZWVuIHJlbW92ZWQsIGZvciBub3cuLi4gCi0gQm90dG9tIHBsb3QgcmVwcmVzZW50aW5nIGluZGV4IGFzIGEgUm1lYW4KCiMjIyMjIEFzIGEgbm9ybWFsIHllYXIgdG8geWVhcgoKYGBge3J9CiMgT3B0aW9uIG9uZQoKZWZmX2luZGV4IDwtIHF1b3RhX2RmICU+JSAKICAjIGZpbHRlcigKICAjICAgc3BwID09IkNlbnRyb3ByaXN0aXMgc3RyaWF0YSIKICAjICkgJT4lIAogIG11dGF0ZShpbmRleCA9IERpc3RyaWJ1dGlvbi9IaXN0b3JpYywKICAgICAgICAgaW5kZXhfcm1lYW4gPSBSTWVhbi9IaXN0b3JpYykgJT4lCiAgZ2F0aGVyKCJsZXZlbCIsImluZGV4IixpbmRleDppbmRleF9ybWVhbikgJT4lCiAgZmlsdGVyKGluZGV4IDwgNSkgIyB0aGVyZSBhcmUgc29tZSBjcmFhYWF6eSBvdXRsaWVycwogICMgVmlldygpCiAgCmdncGxvdChlZmZfaW5kZXgpICsKICBnZW9tX2xpbmUoCiAgICBhZXMoCiAgICAgIHggPSB5ZWFyLAogICAgICB5ID0gaW5kZXgsCiAgICAgIGNvbG9yID0gc3RhdGUKICAgICksCiAgKSArCiAgbGFicyh4ID0gIlllYXIiLHkgPSAiRWZmaWNpZW5jeSBpbmRleCIpICsKICBzY2FsZV9maWxsX21hbnVhbCgiU3RhdGUiLAogICAgdmFsdWVzID0gc3RhdGVfcGFsbGV0LAogICAgbGFiZWxzID0gcXVvdGFfZGYgJT4lIGFycmFuZ2Uob3JkZXIpICU+JSAgcHVsbChzdGF0ZSkgJT4lIHVuaXF1ZSgpCiAgICApICsKICBzY2FsZV9jb2xvcl9tYW51YWwoIlN0YXRlIiwKICAgIHZhbHVlcyA9IHN0YXRlX3BhbGxldCwKICAgIGxhYmVscyA9IHF1b3RhX2RmICU+JSBhcnJhbmdlKG9yZGVyKSAlPiUgIHB1bGwoc3RhdGUpICU+JSB1bmlxdWUoKQogICAgKSArCiAgZmFjZXRfZ3JpZChsZXZlbH5zcHAsCiAgICAgICAgICAgICBzY2FsZXMgPSAiZnJlZSIpKwogIHRoZW1lX2RhcmsoKQoKYGBgCgojIyBOT0FBcyBwb3J0IGFwcHJvYWNoCgpgYGB7ciBub2FhX2xhbmRpbmdzLCBldmFsID0gRiwgZWNobyA9IEZ9Cgpub2FhX2xhbmRpbmdzIDwtIHJlYWQuY3N2KCIvVm9sdW1lcy9FbnRlcnByaXNlL0RhdGEvQWNyb3NzQm91bmRhcmllcy9EYXRhL05PQUEvbGFuZGluZ3NfYnlfdG9wX3VzX3BvcnRzLmNzdiIpCgoKbm9hYV9sYW5kaW5ncyAlPiUgCiAgY2xlYW5fbmFtZXMoKSAlPiUgCiAgVmlldygpCgpzdGF0ZV90b3RhbHMgPC0gYXMuZGF0YS5mcmFtZShzdHJfc3BsaXRfZml4ZWQobm9hYV9sYW5kaW5ncyRQb3J0LiwgIiwiLDIpKSAlPiUgCiAgcmVuYW1lKG5hbWUgPSBWMSwKICAgICAgICAgYWJydiA9IFYyKSAlPiUgCiAgYmluZF9jb2xzKG5vYWFfbGFuZGluZ3MpICU+JSAKICBtdXRhdGUoYWJydiA9IHN0cl9zcXVpc2goYWJydikpICU+JSAKICBjbGVhbl9uYW1lcygpICU+JSAKICBmaWx0ZXIoYWJydiAlaW4lICBjKCJDVCIsIkRFIiwiTUUiLCJNRCIsIk1BIiwiTkgiLCJOSiIsIk5ZIiwiTkMiLCJSSSIsIlZBIikpICU+JSAKICBmaWx0ZXIoeWVhciA+PSAyMDEwKSAlPiUgCiAgZ3JvdXBfYnkoYWJydikgJT4lIAogIHN1bW1hcmlzZSh0b3RhbF9wb3VuZHNfbWlsbGlvbiA9IHN1bShtaWxsaW9uc19vZl9wb3VuZHMpLAogICAgICAgICAgICB0b3RhbF9kbHJfbWlsbGlvbiA9IHN1bSh4X21pbGxpb25zX29mX2RvbGxhcnMpCiAgKQoKIyBFc3RpbWF0ZSBwZXJjZW50YWdlcwpwb3J0X2RhdGEgPC0gYXMuZGF0YS5mcmFtZShzdHJfc3BsaXRfZml4ZWQobm9hYV9sYW5kaW5ncyRQb3J0LiwgIiwiLDIpKSAlPiUgCiAgcmVuYW1lKG5hbWUgPSBWMSwKICAgICAgICAgYWJydiA9IFYyKSAlPiUgCiAgYmluZF9jb2xzKG5vYWFfbGFuZGluZ3MpICU+JSAKICBtdXRhdGUoYWJydiA9IHN0cl9zcXVpc2goYWJydikpICU+JSAKICBjbGVhbl9uYW1lcygpICU+JSAKICBmaWx0ZXIoYWJydiAlaW4lICBjKCJDVCIsIkRFIiwiTUUiLCJNRCIsIk1BIiwiTkgiLCJOSiIsIk5ZIiwiTkMiLCJSSSIsIlZBIikpICU+JSAKICBmaWx0ZXIoeWVhciA+PSAyMDEwKSAlPiUgCiAgZ3JvdXBfYnkoYWJydixuYW1lLHBvcnQpICU+JSAKICBzdW1tYXJpc2Uoc3VtX3BvdW5kc19taWxsaW9uID0gc3VtKG1pbGxpb25zX29mX3BvdW5kcyksCiAgICAgICAgICAgIHN1bV9kbHJfbWlsbGlvbiA9IHN1bSh4X21pbGxpb25zX29mX2RvbGxhcnMpCiAgICAgICAgICAgICkgJT4lIAogIGxlZnRfam9pbihzdGF0ZV90b3RhbHMpICU+JSAKICBtdXRhdGUoCiAgICBwZXJfc3VtID0gc3VtX2Rscl9taWxsaW9uL3RvdGFsX2Rscl9taWxsaW9uKjEwMCwKICAgIHBlcl9wbmRzID0gc3VtX3BvdW5kc19taWxsaW9uL3RvdGFsX3BvdW5kc19taWxsaW9uKjEwMCwKICAgIGN1bV9wZXJfc3VtID0gY3Vtc3VtKHN1bV9kbHJfbWlsbGlvbi90b3RhbF9kbHJfbWlsbGlvbioxMDApLAogICAgY3VtX3Blcl9wbmRzID0gY3Vtc3VtKHN1bV9wb3VuZHNfbWlsbGlvbi90b3RhbF9wb3VuZHNfbWlsbGlvbioxMDApCiAgKQoKIAoKCiAgIyBGdW5jdGlvbiB0byBnZXQgcGVyY2VudGlsZXMKICAgICAgIyBodHRwczovL3d3dy50aWR5dmVyc2Uub3JnL2Jsb2cvMjAyMC8wMy9kcGx5ci0xLTAtMC1zdW1tYXJpc2UvCiAgICAgIHF1aWJibGUgPC0gZnVuY3Rpb24oeCwgcSA9IHApIHsKICAgICAgICB0aWJibGUoeCA9IHF1YW50aWxlKHgsIHEpLCBxID0gcSkKICAgICAgfQogICAgICAjIEdldCB0aGUgcGVyY2VudGlsZSB0cmVzaG9sZCBwZXIgeWVhciwgZW5zZW1ibGUgYW5kIG5laWdoYm91ciBpZAogICAgcGVyY2VudGlsZSA8LSBwb3J0X2RhdGEgJT4lIAogICAgICAgIGdyb3VwX2J5KGFicnYpICU+JQogICAgICAgIGRvKHF1aWJibGUoLiRjb21fc3VtLCAwLjUwKSkgJT4lIAogICAgICBsZWZ0X2pvaW4ocG9ydF9kYXRhKSAlPiUgCiAgICAgIG11dGF0ZShkcm9wID0gaWZlbHNlKHggPCBzdW1fZGxyX21pbGxpb24sImRyb3AiLCJrZWVwIiApKSAlPiUgCiAgICAgIGZpbHRlcihkcm9wID09ICJrZWVwIikKCiAKIAojIE51bWJlciBvZiBwb3J0cyBwZXIgc3RhdGUKcGVyY2VudGlsZSAlPiUKICBncm91cF9ieShhYnJ2KSAlPiUKICBzdW1tYXJpc2UobigpKSAlPiUgCiAgbGVmdF9qb2luKG9yaWdpbmFsX24pICU+JSBWaWV3KCkKCgp1bmlxdWUocG9ydF9kYXRhJGFicnYpCmxlbmd0aCh1bmlxdWUocG9ydF9kYXRhJGFicnYpKQoKIyBHZXQgcmFuayBieSBkb2xhcgp0b3BfZGxyIDwtIHBvcnRfZGF0YSAlPiUgCiAgZ3JvdXBfYnkoYWJydikgJT4lCiAgIyBWaWV3KCkKICB0b3BfbigxMCxzdW1fZGxyX21pbGxpb24pCgojIEdldCByYW5rIGJ5IGxhbmRpbmcKdG9wX3BuZCA8LSBwb3J0X2RhdGEgJT4lIAogIGdyb3VwX2J5KGFicnYpICU+JQogICMgVmlldygpCiAgdG9wX24oMTAsc3VtX3BvdW5kc19taWxsaW9uKQoKIyBCaW5kIHBvcnRzIGFuZCBtYW51YWxseSBzZXQgY29ycmRpbmF0ZXMKdG9wX3BvcnRzIDwtIHRvcF9kbHIgJT4lIAogIGZ1bGxfam9pbih0b3BfcG5kKSAlPiUgCiAgYXJyYW5nZShhYnJ2KSAlPiUgCiAgZ3JvdXBfYnkoYWJydikgJT4lIAogIHN1bW1hcmlzZShuKCkpCiAgCiAgCiAgCiAgCiAgIyBNYW51YWxseSBlc3RpbWF0ZWQgZnJvbSBnb29nbGUgbWFwcwogIGJpbmRfY29scygKICAgIGxhdCA9IGMoNDEuMzM0NTQ3NjgxNjc0NCwKICAgICAgICAgICAgNDEuMzQxMzgzODg2MDA1NjksCiAgICAgICAgICAgIDQxLjYzNjQ2NzA2NTYyNjUwNSwKICAgICAgICAgICAgMzguMzIzNDc3ODc3MjAyNjIsIAogICAgICAgICAgICA0NC4xNTM4NjU0MTUxOTIwMiwgCiAgICAgICAgICAgIDQzLjY2NjE3MzU3ODc2MjkzLAogICAgICAgICAgICAzNS45MDQwMDk4NDUwODA1NCwgCiAgICAgICAgICAgIDQzLjExMjM4MzgzMTI4ODksCiAgICAgICAgICAgIDM4Ljk3MTM5NDAxODc1MDI5NiwgCiAgICAgICAgICAgIDQxLjA1MjY4MzE4MTc5MDA5LCAKICAgICAgICAgICAgNDEuMzcwNTQ4MDA4MjM4OTYsIAogICAgICAgICAgICAzNi45OTI4NTg2MDEzMjk4MzYsIAogICAgICAgICAgICAzNy44Mzk2MzcxMzcyNDkyMzQKICAgICAgICAgICAgKSwKICAgIGxvbmcgPSBjKC03MS45MTMzMjc0NDAyODE5NiwKICAgICAgICAgICAgIC03Mi4wODIwMjU1NjU0NTg1OCwKICAgICAgICAgICAgIC03MC45MTk2NDQ0NjI2NTIxNiwKICAgICAgICAgICAgIC03NS4xMDE0MTgzNDg0MTYzLAogICAgICAgICAgICAgLTY4LjY2NDAyMTk2Nzc1OTgxLAogICAgICAgICAgICAgLTcwLjIyODgzODAxOTY5ODEsCiAgICAgICAgICAgICAtNzUuNTU1NTQwNTk2MTM3MTgsCiAgICAgICAgICAgICAtNzAuODU4MTU4NjY0OTU0ODQsCiAgICAgICAgICAgICAtNzQuODEyMjQxMzgyNjUwNywKICAgICAgICAgICAgIC03MS45Njg4MjU0NjI4OTM2LAogICAgICAgICAgICAgLTcxLjQ4MDMyNDUyNzI2MDgzLAogICAgICAgICAgICAgLTc2LjI2ODE3MTQ2NzMwMzk5LAogICAgICAgICAgICAgIC03Ni4yNDI5Mjc3MTkxNDk1NQogICAgICAgICAgICAgKQogICkgJT4lIAogICMgRGVsYXdhcmUKICBiaW5kX3Jvd3MoCiAgICBkYXRhLmZyYW1lKGFicnYgPSAiREUiLAogICAgICBuYW1lID0gIkluZGlhbiByaXZlciIsCiAgICAgIHBvcnQgPSAiSW5kaWFuIHJpdmVyLCBERSIsCiAgICAgIGxhdCA9IGFzLmRvdWJsZSgzOC42MjExMzU5MzQwMzc0NiksCiAgICAgIGxvbmcgPSAtNzUuMDYzOTcwMjE3MTgzNDUKICAgICAgKQogICkKCiMgd3JpdGVfY3N2KHRvcF9wb3J0cywidG9wX25ldXNfcG9ydHMuY3N2IikKCgogIHBvcnRfZGF0YSAlPiUgCiAgICBmaWx0ZXIoY29tX21lYW4gPj0gNzUpICU+JSAKICAgIGdyb3VwX2J5KGFicnYpICU+JSAKICAgIFZpZXcoKQogICAgc3VtbWFyaXNlKG4oKSkKCmBgYAoKCmBgYHtyIHJlbW92ZV9wZW4sIGV2YWwgPSBGLCBlY2hvID0gRn0KCiMjIyNfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXyMjIyAKIyBTb2x2aW5nIGZvciBJc3N1ZSAjOCBQZW5uc3lsdmFuaWEgaGFzIE5PIGNvYXN0CiMjIyNfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXyMjIyAKCiMgUmVtb3ZlIFBlbm5zeWx2YW5pYSBmcm9tIHNmCmdyaWRfZWV6X3NmIDwtICBzdF9yZWFkKCIvVm9sdW1lcy9FbnRlcnByaXNlL0RhdGEvQWNyb3NzQm91bmRhcmllcy9EYXRhL1NwYXRpYWwvZ3JpZF9zZi9ncmlkX2Vlel9zZi5zaHAiKSAlPiUKICBmaWx0ZXIoc3RhdGUgIT0gInBlbm5zeWx2YW5pYSIpCgojIE1ha2Ugc3VyZSBubyBQZW5uLgp1bmlxdWUoZ3JpZF9lZXpfc2Ykc3RhdGUpCgojIG92ZXIgd3JpdGUgc2YKd3JpdGVfc2YoZ3JpZF9lZXpfc2YsIHBhc3RlMChteV9wYXRoKCJEIiwgIlNwYXRpYWwiKSwiZ3JpZF9lZXpfc2Yuc2hwIikpCgojTWFrZSBzdXJlIG9mIHRoaW5ncwoKIyBncmlkX2Vlel9zZiA8LSAgc3RfcmVhZCgiL1ZvbHVtZXMvRW50ZXJwcmlzZS9EYXRhL0Fjcm9zc0JvdW5kYXJpZXMvRGF0YS9TcGF0aWFsL2dyaWRfc2YvZ3JpZF9lZXpfc2Yuc2hwIikKCiMgdW5pcXVlKGdyaWRfZWV6X3NmJHN0YXRlKQoKIyBOb3cgc2F2ZSBpdCBhcyBhIERGIHRvbwoKIyBncmlkX2Vlel9kZiA8LSBhcy5kYXRhLmZyYW1lKGdyaWRfZWV6X3NmKSAlPiUKICAjIHNlbGVjdChzdGF0ZSxpbmRleCkgJT4lCiAgIyBsZWZ0X2pvaW4obmVfZ3JpZCwKICAgICAgICAgICAgIyBieSA9ICJpbmRleCIpCgojIHdyaXRlX2NzdihncmlkX2Vlel9kZiwgcGFzdGUwKG15X3BhdGgoIlIiLCAiUGFydGlhbCIpLCJncmlkX2Vlel9kZi5jc3YiKSkKYGBgCgojIyMgRHluYW1pYyBmaWd1cmU6IEFnZ3JlZ2F0ZWQgUHJvcG9ydGlvbmFsIGNoYW5nZSBwZXIgc3VydmV5CgpgYGB7ciBhcmVhX21hcF9hZ2dyZWdhdGVkLCBldmFsID0gVCwgZWNobyA9IFQsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0PTZ9Cgp0b3RhbF9maXRlZCA8LSBoaXN0b3JpY19zcHAgJT4lIAogIGdyb3VwX2J5KHllYXIscmVnaW9uLHNwYXRpYWwpICU+JSAKICBzdW1tYXJpc2UodG90YWxfdmFsdWUgPSBzdW0odmFsdWUsbmEucm09VCksLmdyb3VwcyA9ICJkcm9wIikKCgpzdGF0ZV9maXQgPC0gaGlzdG9yaWNfc3BwICU+JSAKICBncm91cF9ieShzdGF0ZSx5ZWFyLHJlZ2lvbixzcGF0aWFsKSAlPiUgCiAgc3VtbWFyaXNlKHN0YXRlX3ZhbHVlID0gc3VtKHZhbHVlLG5hLnJtPSBUKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lIAogIGxlZnRfam9pbih0b3RhbF9maXRlZCwKICAgICAgICAgICAgYnkgPSBjKCJ5ZWFyIiwicmVnaW9uIiwic3BhdGlhbCIpKSAlPiUKICBtdXRhdGUocGVyY2VudGFnZSA9IHN0YXRlX3ZhbHVlL3RvdGFsX3ZhbHVlKjEwMCkgJT4lIAogIGxlZnRfam9pbihwZXJpb2RzLAogICAgICAgICAgICBieSA9ICJ5ZWFyIikgJT4lIAogIGdyb3VwX2J5KHN0YXRlLG9yZGVyLGxhYmVsLHJlZ2lvbixzcGF0aWFsKSAlPiUgCiAgc3VtbWFyaXNlKG1lYW5fcGVyID0gcm91bmQobWVhbihwZXJjZW50YWdlKSksLmdyb3VwcyA9ICJkcm9wIikKCiMgY2hlY2sgcGVyY2VudGFnZXMKIyBzdGF0ZV9maXQgJT4lIAojICAgZ3JvdXBfYnkocGVyaW9kKSAlPiUgCiMgICBzdW1tYXJpc2Uoc3VtKG1lYW5fcGVyKSkKCgpwIDwtIGxhbmRfc2YgJT4lIAogIGxlZnRfam9pbihzdGF0ZV9maXQsCiAgICAgICAgICAgIGJ5ID0gInN0YXRlIikgJT4lIAogIGdncGxvdCgpICsKICAjIGdlb21fc2YoYWVzKGZpbGwgPSBtZWFuX3BlcikpICsKICBnZW9tX3NmKGFlcyhmaWxsID0gbWVhbl9wZXIsIHRleHQgPSBwYXN0ZShzdGF0ZSwgbWVhbl9wZXIsIiUgb2YgcHJvcG9ydGlvbiIpKSkgKwogIHZpcmlkaXM6OnNjYWxlX2ZpbGxfdmlyaWRpcygiQXZlcmFnZSBwcm9wb3J0aW9uIHBlciBTdGF0ZSIsIGFscGhhID0gMC44KSArCiAgZmFjZXRfd3JhcCh+IHJlZ2lvbiArIGxhYmVsICtzcGF0aWFsLCAKICAgICAgICAgICAgIG5yb3cgPSAyKSArCiAgbGFicyh4ID0gIkxhdGl0dWRlIiwgCiAgICAgICB5ID0gIkxvbmdpdHVkZSIpICsKICBteV9nZ3RoZW1lX3AoZmFjZXRfdHhfcyA9IDEyLAogICAgICAgICAgICAgICBsZWdfcG9zID0gImJvdHRvbSIpICsKICB0aGVtZShsZWdlbmQua2V5LndpZHRoID0gdW5pdCgxLCJsaW5lIikpICsKICB0aGVtZV9kYXJrKCkKCmdncGxvdGx5KHAsCiAgICAgICAgIHRvb2x0aXAgPSAidGV4dCIsCiAgICAgICAgIGR5bmFtaWNUaWNrcyA9IEZBTFNFKSAlPiUgCiAgICBzdHlsZShob3ZlcmxhYmVsID0gbGlzdChiZ2NvbG9yID0gIndoaXRlIiksIGhvdmVyb24gPSAiZmlsbCIpCgoKYGBgCgoKYGBge3IgZXZhbCA9IEYsIGVjaG8gPSBULCByZXN1bHRzPSdoaWRlJ30KCnRvdGFsX2ZpdGVkIDwtIGhpc3RvcmljX3NwcCAlPiUKICBncm91cF9ieSh5ZWFyLHJlZ2lvbixzcHAsc3BhdGlhbCkgJT4lCiAgc3VtbWFyaXNlKHRvdGFsX3ZhbHVlID0gc3VtKHZhbHVlLG5hLnJtPVQpLC5ncm91cHMgPSAiZHJvcCIpCgoKc3RhdGVfY2hhbmdlIDwtaGlzdG9yaWNfc3BwICU+JSAKICBncm91cF9ieShzdGF0ZSx5ZWFyLHJlZ2lvbixzcHAsc3BhdGlhbCkgJT4lIAogIHN1bW1hcmlzZShzdGF0ZV92YWx1ZSA9IHN1bSh2YWx1ZSxuYS5ybT0gVCksIC5ncm91cHMgPSAiZHJvcCIpICU+JSAKICBsZWZ0X2pvaW4odG90YWxfZml0ZWQsCiAgICAgICAgICAgIGJ5ID0gYygieWVhciIsInJlZ2lvbiIsInNwcCIsInNwYXRpYWwiKSkgJT4lCiAgbXV0YXRlKHBlcmNlbnRhZ2UgPSBzdGF0ZV92YWx1ZS90b3RhbF92YWx1ZSoxMDAsCiAgICAgICAgIGxhYmVsID0gaWZlbHNlKHllYXIgPj0gMTk4MCAmIHllYXIgPD0gMjAwMSwiUmVmZXJlbmNlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZSh5ZWFyID4gMjAwMSwiVG9kYXkiLE5BKQogICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICApICU+JSAKICBncm91cF9ieShzdGF0ZSxsYWJlbCxyZWdpb24sc3BwLHNwYXRpYWwpICU+JSAKICBzdW1tYXJpc2UobWVhbl9wZXIgPSByb3VuZChtZWFuKHBlcmNlbnRhZ2UpKSwuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgIyBPbmx5IHNob3cgcmVzdWx0cyBmb3Igc3ByaW5nCiAgZmlsdGVyKHN0cl9kZXRlY3QocmVnaW9uLCJTcHJpbmciKSwKICAgICAgICAgIWlzLm5hKGxhYmVsKQogICAgICAgICApICU+JSAKICBzZWxlY3QoLXJlZ2lvbikgJT4lIAogIHNwcmVhZChsYWJlbCxtZWFuX3BlcikgJT4lIAogIG11dGF0ZShjaGFuZ2UgPSAoVG9kYXktUmVmZXJlbmNlKS8oVG9kYXkpKjEwMCwKICAgICAgICAgY2hhbmdlID0gaWZlbHNlKGNoYW5nZSA+IDEwMCwxMDAsCiAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoY2hhbmdlIDwgLTEwMCwtMTAwLGNoYW5nZSkKICAgICAgICAgKQogICkgJT4lCiAgc2VsZWN0KC00LC01KSAlPiUgCiAgc3ByZWFkKHNwYXRpYWwsY2hhbmdlKSAlPiUgCiAgbXV0YXRlKAogICAgI2RpZmZlcmVuY2UgPSAoZnAtc3cpLygoZnArc3cpLzIpKjEwMCwKICAgIGRpZmZlcmVuY2UgPSBhYnMoZnAtc3cpIywKICAgICAgICAgIyBkaWZmZXJlbmNlID0gaWZlbHNlKGRpZmZlcmVuY2UgPiAxMDAsMTAwLAogICAgICAgICAjICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRpZmZlcmVuY2UgPCAtMTAwLC0xMDAsZGlmZmVyZW5jZSkKICAgICAgICAgIyApCiAgKSAlPiUgCiAgZ2F0aGVyKCJzcGF0aWFsIiwibWVhbl9wZXIiLGZwOmRpZmZlcmVuY2UpICU+JSAKICBtdXRhdGUoCiAgICAgICAgIHNwYXRpYWwgPSBpZmVsc2Uoc3BhdGlhbCA9PSAiZnAiLCJGaXNoaW5nIHBvcnRzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uoc3BhdGlhbCA9PSAic3ciLCJTdGF0ZSBXYXRlcnMiLCJEaWZmZXJlbmNlIikKICAgICAgICAgKSwKICAgICAgICAgbWVhbl9wZXI9IHJlcGxhY2VfbmEobWVhbl9wZXIsMCkjIGZvciB0aG9zZSAwLzAKICApCiAgIAoKIyBUaGUgcGxvdApwcm9wX2NobmdfbWFwIDwtIGxhbmRfc2YgJT4lIAogIGxlZnRfam9pbihzdGF0ZV9jaGFuZ2UsCiAgICAgICAgICAgIGJ5ID0gInN0YXRlIikgJT4lIAogIGZpbHRlcihzcGF0aWFsICE9ICJEaWZmZXJlbmNlIikgJT4lIAogIGdncGxvdCgpICsKICBnZW9tX3NmKGFlcyhmaWxsID0gbWVhbl9wZXIpKSArCiAgdmlyaWRpczo6c2NhbGVfZmlsbF92aXJpZGlzKCJDaGFuZ2UgaW4gcHJvcG9ydGlvbiB0b2RheVxucmVsYXRpdmUgdG8gMTk4MC0yMDAxXG4oJSkiLCBhbHBoYSA9IDAuOCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygtMTAwLDEwMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgtMTAwLDEwMCwyNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjwtMTAwIixzZXEoLTc1LDc1LDI1KSwiPjEwMCIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgKwogIGZhY2V0X2dyaWQoc3BhdGlhbH4gc3BwKSArCiAgbGFicyh4ID0gIiIsIAogICAgICAgeSA9ICIiKSArCiAgbXlfZ2d0aGVtZV9wKGZhY2V0X3R4X3MgPSAyMCwKICAgICAgICAgICAgICAgbGVnX3BvcyA9ICJib3R0b20iLAogICAgICAgICAgICAgICBheHhfdHhfYW5nID0gNDUsCiAgICAgICAgICAgICAgIGF4X3R4X3MgPSAxMiwKICAgICAgICAgICAgICAgYXhfdGxfcyA9IDE4LAogICAgICAgICAgICAgICBoanVzdCA9IDEpICsKICB0aGVtZShsZWdlbmQua2V5LndpZHRoID0gdW5pdCg0LCJsaW5lIiksCiAgICAgICAgbGVnZW5kLnRpdGxlLmFsaWduPTAuNSkgCgojIGdnc2F2ZShmaWxlbmFtZSA9ICJ0ZW1wX3Byb3BvcnRpb25fY2huZy5qcGciLAojICAgICAgICAgIHBsb3QgPSBwcm9wX2NobmdfbWFwLAojICAgICAgICAgIHBhdGggPSBteV9wYXRoKCJSIiwiRmlndXJlcyIpLAojICAgICAgICAgIHdpZHRoID0gMTAsCiMgICAgICAgICAgaGVpZ2h0ID0gMTAKIyAgICkKCgojIyMjIE9wdGlvbiB3aXRoIGRpZmZlcmVuY2VzCgpwcm9wX2NobmdfbWFwX2RpZmYgPC0gbGFuZF9zZiAlPiUgCiAgbGVmdF9qb2luKHN0YXRlX2NoYW5nZSwKICAgICAgICAgICAgYnkgPSAic3RhdGUiKSAlPiUgCiAgZmlsdGVyKHNwYXRpYWwgPT0gIkRpZmZlcmVuY2UiKSAlPiUgCiAgZ2dwbG90KCkgKwogIGdlb21fc2YoYWVzKGZpbGwgPSBtZWFuX3BlcikpICsKICB2aXJpZGlzOjpzY2FsZV9maWxsX3ZpcmlkaXMoIkNoYW5nZSBpbiBwcm9wb3J0aW9uIHRvZGF5XG5yZWxhdGl2ZSB0byAxOTgwLTIwMDFcbiglKSIsIGFscGhhID0gMC44LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcHRpb24gPSAiQyIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygtMTAwLDEwMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgtMTAwLDEwMCwyNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjwtMTAwIixzZXEoLTc1LDc1LDI1KSwiPjEwMCIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgKwogIGZhY2V0X2dyaWQoc3BhdGlhbH4gc3BwKSArCiAgbGFicyh4ID0gIiIsIAogICAgICAgeSA9ICIiKSArCiAgbXlfZ2d0aGVtZV9wKGZhY2V0X3R4X3MgPSAyMCwKICAgICAgICAgICAgICAgbGVnX3BvcyA9ICJib3R0b20iLAogICAgICAgICAgICAgICBheHhfdHhfYW5nID0gNDUsCiAgICAgICAgICAgICAgIGF4X3R4X3MgPSAxMiwKICAgICAgICAgICAgICAgYXhfdGxfcyA9IDE4LAogICAgICAgICAgICAgICBoanVzdCA9IDEpICsKICB0aGVtZShsZWdlbmQua2V5LndpZHRoID0gdW5pdCg0LCJsaW5lIiksCiAgICAgICAgbGVnZW5kLnRpdGxlLmFsaWduPTAuNSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSkKCgojIENvd3Bsb3Qgb3B0aW9uCnAgPC0gZ2dkcmF3KCkgKwogICMgUmV2ZW51ZSBjaXJjdWxhcgogIGRyYXdfcGxvdChwcm9wX2NobmdfbWFwLCB4ID0gMCwgeSA9IDAuMjUsIHdpZHRoID0gMSwgaGVpZ2h0ID0gMC42NSkgKwogICMgQ2F0Y2ggY2lyY3VsYXIKICBkcmF3X3Bsb3QocHJvcF9jaG5nX21hcF9kaWZmLCB4ID0gMC4xMDEsIHkgPSAwLCB3aWR0aCA9IDAuNzk4LCBoZWlnaHQgPSAwLjQpICsKICBkcmF3X3Bsb3RfbGFiZWwobGFiZWwgPSBjKCJMYXRpdHVkZSIsICJMb25naXR1ZGUiKSwgCiAgICAgICAgICAgICAgICAgIHNpemUgPSAxNiwKICAgICAgICAgICAgICAgICAgYW5nbGUgPSBjKDkwLDApLAogICAgICAgICAgICAgICAgICB4ID0gYygwLjEsMC40NSksIAogICAgICAgICAgICAgICAgICB5ID0gYygwLjQ1LDAuMTEpCiAgKQogICAgCgpzYXZlX3Bsb3QoCiAgcGF0aCA9IG15X3BhdGgoIlIiLCJGaWd1cmVzIiksCiAgInByb3BvcnRpb25fY2hnX2RpZmZOLmpwZyIsCiAgcCwKICBiYXNlX2hlaWdodCA9IDE0LAogIGJhc2Vfd2lkdGggPSAxNAopCgpgYGAKCgojIyMgUHJvcG9ydGlvbiBjaGFuZ2UgcmVhbHRpdmUgdG8gcGFzdAoKYGBge3IgcGFwZXJfZmlndXJlX2FyZWFfbWFwLCBldmFsID0gRiwgZWNobyA9IFQsIHJlc3VsdHM9J2hpZGUnfQoKdG90YWxfZml0ZWQgPC0gaGlzdG9yaWNfc3BwICU+JQogIGdyb3VwX2J5KHllYXIsc2Vhc29uLHNwcCxzcGF0aWFsKSAlPiUKICBzdW1tYXJpc2UodG90YWxfdmFsdWUgPSBzdW0odmFsdWUsbmEucm09VCksLmdyb3VwcyA9ICJkcm9wIikKCgpzdGF0ZV9jaGFuZ2UgPC1oaXN0b3JpY19zcHAgJT4lIAogIGdyb3VwX2J5KHN0YXRlLHllYXIsc2Vhc29uLHNwcCxzcGF0aWFsKSAlPiUgCiAgc3VtbWFyaXNlKHN0YXRlX3ZhbHVlID0gc3VtKHZhbHVlLG5hLnJtPSBUKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lIAogIGxlZnRfam9pbih0b3RhbF9maXRlZCwKICAgICAgICAgICAgYnkgPSBjKCJ5ZWFyIiwicmVnaW9uIiwic3BwIiwic3BhdGlhbCIpKSAlPiUKICBtdXRhdGUocGVyY2VudGFnZSA9IHN0YXRlX3ZhbHVlL3RvdGFsX3ZhbHVlKjEwMCwKICAgICAgICAgbGFiZWwgPSBpZmVsc2UoeWVhciA+PSAxOTgwICYgeWVhciA8PSAyMDAxLCJSZWZlcmVuY2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHllYXIgPiAyMDAxLCJUb2RheSIsTkEpCiAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICkgJT4lIAogIGdyb3VwX2J5KHN0YXRlLGxhYmVsLHJlZ2lvbixzcHAsc3BhdGlhbCkgJT4lIAogIHN1bW1hcmlzZShtZWFuX3BlciA9IHJvdW5kKG1lYW4ocGVyY2VudGFnZSkpLC5ncm91cHMgPSAiZHJvcCIpICU+JSAKICAjIE9ubHkgc2hvdyByZXN1bHRzIGZvciBzcHJpbmcKICBmaWx0ZXIoc3RyX2RldGVjdChyZWdpb24sIlNwcmluZyIpLAogICAgICAgICAhaXMubmEobGFiZWwpCiAgICAgICAgICkgJT4lIAogIHNlbGVjdCgtcmVnaW9uKSAlPiUgCiAgc3ByZWFkKGxhYmVsLG1lYW5fcGVyKSAlPiUgCiAgbXV0YXRlKGNoYW5nZSA9IChUb2RheS1SZWZlcmVuY2UpLyhUb2RheSkqMTAwLAogICAgICAgICBjaGFuZ2UgPSBpZmVsc2UoY2hhbmdlID4gMTAwLDEwMCwKICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShjaGFuZ2UgPCAtMTAwLC0xMDAsY2hhbmdlKQogICAgICAgICApCiAgKSAlPiUKICBzZWxlY3QoLTQsLTUpICU+JSAKICBzcHJlYWQoc3BhdGlhbCxjaGFuZ2UpICU+JSAKICBtdXRhdGUoCiAgICAjZGlmZmVyZW5jZSA9IChmcC1zdykvKChmcCtzdykvMikqMTAwLAogICAgZGlmZmVyZW5jZSA9IGFicyhmcC1zdykjLAogICAgICAgICAjIGRpZmZlcmVuY2UgPSBpZmVsc2UoZGlmZmVyZW5jZSA+IDEwMCwxMDAsCiAgICAgICAgICMgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGlmZmVyZW5jZSA8IC0xMDAsLTEwMCxkaWZmZXJlbmNlKQogICAgICAgICAjICkKICApICU+JSAKICBnYXRoZXIoInNwYXRpYWwiLCJtZWFuX3BlciIsZnA6ZGlmZmVyZW5jZSkgJT4lIAogIG11dGF0ZSgKICAgICAgICAgc3BhdGlhbCA9IGlmZWxzZShzcGF0aWFsID09ICJmcCIsIkZpc2hpbmcgcG9ydHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShzcGF0aWFsID09ICJzdyIsIlN0YXRlIFdhdGVycyIsIkRpZmZlcmVuY2UiKQogICAgICAgICApLAogICAgICAgICBtZWFuX3Blcj0gcmVwbGFjZV9uYShtZWFuX3BlciwwKSMgZm9yIHRob3NlIDAvMAogICkKICAgCgojIFRoZSBwbG90CnByb3BfY2huZ19tYXAgPC0gbGFuZF9zZiAlPiUgCiAgbGVmdF9qb2luKHN0YXRlX2NoYW5nZSwKICAgICAgICAgICAgYnkgPSAic3RhdGUiKSAlPiUgCiAgZmlsdGVyKHNwYXRpYWwgIT0gIkRpZmZlcmVuY2UiKSAlPiUgCiAgZ2dwbG90KCkgKwogIGdlb21fc2YoYWVzKGZpbGwgPSBtZWFuX3BlcikpICsKICB2aXJpZGlzOjpzY2FsZV9maWxsX3ZpcmlkaXMoIkNoYW5nZSBpbiBwcm9wb3J0aW9uIHRvZGF5XG5yZWxhdGl2ZSB0byAxOTgwLTIwMDFcbiglKSIsIGFscGhhID0gMC44LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKC0xMDAsMTAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKC0xMDAsMTAwLDI1KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiPC0xMDAiLHNlcSgtNzUsNzUsMjUpLCI+MTAwIikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSArCiAgZmFjZXRfZ3JpZChzcGF0aWFsfiBzcHApICsKICBsYWJzKHggPSAiIiwgCiAgICAgICB5ID0gIiIpICsKICBteV9nZ3RoZW1lX3AoZmFjZXRfdHhfcyA9IDIwLAogICAgICAgICAgICAgICBsZWdfcG9zID0gImJvdHRvbSIsCiAgICAgICAgICAgICAgIGF4eF90eF9hbmcgPSA0NSwKICAgICAgICAgICAgICAgYXhfdHhfcyA9IDEyLAogICAgICAgICAgICAgICBheF90bF9zID0gMTgsCiAgICAgICAgICAgICAgIGhqdXN0ID0gMSkgKwogIHRoZW1lKGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDQsImxpbmUiKSwKICAgICAgICBsZWdlbmQudGl0bGUuYWxpZ249MC41KSAKCiMgZ2dzYXZlKGZpbGVuYW1lID0gInRlbXBfcHJvcG9ydGlvbl9jaG5nLmpwZyIsCiMgICAgICAgICAgcGxvdCA9IHByb3BfY2huZ19tYXAsCiMgICAgICAgICAgcGF0aCA9IG15X3BhdGgoIlIiLCJGaWd1cmVzIiksCiMgICAgICAgICAgd2lkdGggPSAxMCwKIyAgICAgICAgICBoZWlnaHQgPSAxMAojICAgKQoKCiMjIyMgT3B0aW9uIHdpdGggZGlmZmVyZW5jZXMKCnByb3BfY2huZ19tYXBfZGlmZiA8LSBsYW5kX3NmICU+JSAKICBsZWZ0X2pvaW4oc3RhdGVfY2hhbmdlLAogICAgICAgICAgICBieSA9ICJzdGF0ZSIpICU+JSAKICBmaWx0ZXIoc3BhdGlhbCA9PSAiRGlmZmVyZW5jZSIpICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV9zZihhZXMoZmlsbCA9IG1lYW5fcGVyKSkgKwogIHZpcmlkaXM6OnNjYWxlX2ZpbGxfdmlyaWRpcygiQ2hhbmdlIGluIHByb3BvcnRpb24gdG9kYXlcbnJlbGF0aXZlIHRvIDE5ODAtMjAwMVxuKCUpIiwgYWxwaGEgPSAwLjgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbiA9ICJDIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKC0xMDAsMTAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKC0xMDAsMTAwLDI1KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiPC0xMDAiLHNlcSgtNzUsNzUsMjUpLCI+MTAwIikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSArCiAgZmFjZXRfZ3JpZChzcGF0aWFsfiBzcHApICsKICBsYWJzKHggPSAiIiwgCiAgICAgICB5ID0gIiIpICsKICBteV9nZ3RoZW1lX3AoZmFjZXRfdHhfcyA9IDIwLAogICAgICAgICAgICAgICBsZWdfcG9zID0gImJvdHRvbSIsCiAgICAgICAgICAgICAgIGF4eF90eF9hbmcgPSA0NSwKICAgICAgICAgICAgICAgYXhfdHhfcyA9IDEyLAogICAgICAgICAgICAgICBheF90bF9zID0gMTgsCiAgICAgICAgICAgICAgIGhqdXN0ID0gMSkgKwogIHRoZW1lKGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDQsImxpbmUiKSwKICAgICAgICBsZWdlbmQudGl0bGUuYWxpZ249MC41LAogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKQoKCiMgQ293cGxvdCBvcHRpb24KcCA8LSBnZ2RyYXcoKSArCiAgIyBSZXZlbnVlIGNpcmN1bGFyCiAgZHJhd19wbG90KHByb3BfY2huZ19tYXAsIHggPSAwLCB5ID0gMC4yNSwgd2lkdGggPSAxLCBoZWlnaHQgPSAwLjY1KSArCiAgIyBDYXRjaCBjaXJjdWxhcgogIGRyYXdfcGxvdChwcm9wX2NobmdfbWFwX2RpZmYsIHggPSAwLjEwMSwgeSA9IDAsIHdpZHRoID0gMC43OTgsIGhlaWdodCA9IDAuNCkgKwogIGRyYXdfcGxvdF9sYWJlbChsYWJlbCA9IGMoIkxhdGl0dWRlIiwgIkxvbmdpdHVkZSIpLCAKICAgICAgICAgICAgICAgICAgc2l6ZSA9IDE2LAogICAgICAgICAgICAgICAgICBhbmdsZSA9IGMoOTAsMCksCiAgICAgICAgICAgICAgICAgIHggPSBjKDAuMSwwLjQ1KSwgCiAgICAgICAgICAgICAgICAgIHkgPSBjKDAuNDUsMC4xMSkKICApCiAgICAKCnNhdmVfcGxvdCgKICBwYXRoID0gbXlfcGF0aCgiUiIsIkZpZ3VyZXMiKSwKICAicHJvcG9ydGlvbl9jaGdfZGlmZk4uanBnIiwKICBwLAogIGJhc2VfaGVpZ2h0ID0gMTQsCiAgYmFzZV93aWR0aCA9IDE0CikKCmBgYAoKCgoKIyMjIEFnZ3JlZ2F0ZWQgUHJvcG9ydGlvbmFsIGNoYW5nZQoKYGBge3IgYXJlYV9tYXBfYWdncmVnYXRlZF9mb3JtYW5zLCBldmFsID0gVCwgZWNobyA9IFQsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0PTZ9Cgp0b3RhbF9maXRlZCA8LSBoaXN0b3JpY19zcHAgJT4lCiAgZ3JvdXBfYnkoeWVhcixyZWdpb24sc3BhdGlhbCkgJT4lCiAgc3VtbWFyaXNlKHRvdGFsX3ZhbHVlID0gc3VtKHZhbHVlLG5hLnJtPVQpLC5ncm91cHMgPSAiZHJvcCIpCgoKc3RhdGVfY2hhbmdlIDwtIGhpc3RvcmljX3NwcCAlPiUgCiAgZ3JvdXBfYnkoc3RhdGUseWVhcixyZWdpb24sc3BhdGlhbCkgJT4lIAogIHN1bW1hcmlzZShzdGF0ZV92YWx1ZSA9IHN1bSh2YWx1ZSxuYS5ybT0gVCksIC5ncm91cHMgPSAiZHJvcCIpICU+JSAKICBsZWZ0X2pvaW4odG90YWxfZml0ZWQsCiAgICAgICAgICAgIGJ5ID0gYygieWVhciIsInJlZ2lvbiIsInNwYXRpYWwiKSkgJT4lCiAgbXV0YXRlKHBlcmNlbnRhZ2UgPSBzdGF0ZV92YWx1ZS90b3RhbF92YWx1ZSoxMDAsCiAgICAgICAgIGxhYmVsID0gaWZlbHNlKHllYXIgPj0gMTk4MCAmIHllYXIgPD0gMjAwMSwicmVmZXJlbmNlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZSh5ZWFyID4gMjAwMSwidG9kYXkiLE5BKQogICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICApICU+JSAKICAjIGxlZnRfam9pbihwZXJpb2RzLAogICAgICAgICAgICAjIGJ5ID0gInllYXIiKSAlPiUgCiAgZ3JvdXBfYnkoc3RhdGUsbGFiZWwscmVnaW9uLHNwYXRpYWwpICU+JSAKICBzdW1tYXJpc2UobWVhbl9wZXIgPSByb3VuZChtZWFuKHBlcmNlbnRhZ2UpKSwuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgI09ubHkgc2hvdyByZXN1bHRzIGZvciBzcHJpbmcKICBmaWx0ZXIoI3N0cl9kZXRlY3QocmVnaW9uLCJTcHJpbmciKSwKICAgICAgICAgIWlzLm5hKGxhYmVsKQogICAgICAgICApICU+JSAKICAjIHNlbGVjdCgtcmVnaW9uKSAlPiUgCiAgIyBFc3RpbWF0ZSBwZXJjZW50YWdlIGNoYW5nZQogIHNwcmVhZChsYWJlbCxtZWFuX3BlcikgJT4lIAogIG11dGF0ZShyYXdfY2hhbmdlID0gKHRvZGF5LXJlZmVyZW5jZSkvKHRvZGF5KSoxMDAsCiAgICAgICAgIGNoYW5nZSA9IGlmZWxzZShyYXdfY2hhbmdlID4gMTAwLDEwMCwKICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShyYXdfY2hhbmdlIDwgLTEwMCwtMTAwLHJhd19jaGFuZ2UpCiAgICAgICAgICkKICApICU+JQogIHNlbGVjdCgtcmVmZXJlbmNlLC10b2RheSkgCgoKIyMjIyBBdmVyYWdlCnN0YXRlX2NoYW5nZSAlPiUgCiAgbXV0YXRlKAogICAgd2wgPSBpZmVsc2UoY2hhbmdlIDwgMCwgIkwiLAogICAgICAgICAgICAgICAgaWZlbHNlKGNoYW5nZSA9PSAwLCAiTkMiLCJXIikpCiAgKSAlPiUgCiAgIyBWaWV3KCkKICAjIGdyb3VwX2J5KHdsKSAlPiUgCiAgZ3JvdXBfYnkocmVnaW9uLHNwYXRpYWwsd2wpICU+JSAKICBzdW1tYXJpc2UoCiAgICBzdGF0ZXMgPSBwYXN0ZSh1bmlxdWUoc3RhdGUpLGNvbGxhcHNlID0gIiwgIiksCiAgICBtZWFuKHJhd19jaGFuZ2UpLAogICAgc2QocmF3X2NoYW5nZSkKICApICU+JSAKICB3cml0ZV9jc3YoIi4uL1Jlc3VsdHMvc3RhdGVfcmVsYXRpdmVfY2huZy5jc3YiKQogIFZpZXcoKQoKCgogICMgRXN0aW1hdGUgc3BhdGlhbCBkaWZmZXJlbmNlcyBpbiBwZXJjZW50YWdlIGNoYW5nZQpzcGF0aWFsX2RpZmYgPC0gc3RhdGVfY2hhbmdlICU+JSAKICBzcHJlYWQoc3BhdGlhbCxjaGFuZ2UpICU+JSAKICBtdXRhdGUoc3BhdGlhbF9kaWZmID0gYWJzKGZwLXN3KSkgJT4lIAogIHNlbGVjdChzdGF0ZSwgY2F0ZWdvcnkgPSByZWdpb24sIGRpZmYgPSBzcGF0aWFsX2RpZmYpCgojIEVzdGltYXRlIHNlYXNvbmFsIGRpZmZlcmVuY2VzIGluIHBlcmNlbnRhZ2UgY2hhbmdlCnNlYXNvbl9kaWZmIDwtIHN0YXRlX2NoYW5nZSAlPiUgCiAgc3ByZWFkKHJlZ2lvbixjaGFuZ2UpICU+JSAgCiAgbXV0YXRlKHNlYXNvbl9kaWZmID0gYWJzKGBOb3J0aGVhc3QgVVMgRmFsbGAtYE5vcnRoZWFzdCBVUyBTcHJpbmdgKSkgJT4lIAogIHNlbGVjdChzdGF0ZSxjYXRlZ29yeSA9IHNwYXRpYWwsZGlmZiA9IHNlYXNvbl9kaWZmKQoKZGlmZmVyZW5jZXMgPC0gc2Vhc29uX2RpZmYgJT4lIAogIGJpbmRfcm93cyhzcGF0aWFsX2RpZmYpICU+JSAKICBtdXRhdGUoCiAgICBsYWJlbCA9IGlmZWxzZShjYXRlZ29yeSA9PSAiZnAiLCJGaXNoaW5nIHBvcnRzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoY2F0ZWdvcnkgPT0gInN3IiwiU3RhdGUgV2F0ZXJzIixjYXRlZ29yeSkKICAgICAgICAgKQogICkKCiMgRm9yIGluIHRleHQgZGlmZmVyZW5jZXMKZGlmZmVyZW5jZXMgJT4lIAogIGdyb3VwX2J5KGNhdGVnb3J5KSAlPiUKICBzdW1tYXJpc2VfYXQodmFycyhkaWZmKSwKICAgIGMobWVhbiA9IG1lYW4sCiAgICAgIHNkID1zZCwKICAgICAgbWluID0gbWluLAogICAgICBtYXg9IG1heCkpCgoKIyBUaGUgbWFpbiBwbG90CnByb3BfY2huZ19tYXAgPC0gbGFuZF9zZiAlPiUgCiAgbGVmdF9qb2luKHN0YXRlX2NoYW5nZSwKICAgICAgICAgICAgYnkgPSAic3RhdGUiKSAlPiUgCiAgIyBmaWx0ZXIoc3BhdGlhbCAhPSAiRGlmZmVyZW5jZSIgJiBjYXQgIT0gImRpZmZlcmVuY2VfcmVnIikgJT4lIAogIGdncGxvdCgpICsKICBnZW9tX3NmKGFlcyhmaWxsID0gY2hhbmdlKSkgKwogIHZpcmlkaXM6OnNjYWxlX2ZpbGxfdmlyaWRpcygiQ2hhbmdlIGluIHByb3BvcnRpb24gdG9kYXlcbiByZWxhdGl2ZSB0byAxOTczLTE5ODRcbiglKSIsIGFscGhhID0gMC44LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKC0xMDAsMTAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKC0xMDAsMTAwLDI1KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYyhzZXEoLTEwMCw3NSwyNSksIj4xMDAiKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICsKICBmYWNldF9ncmlkKHNwYXRpYWx+IHJlZ2lvbikgKwogIGxhYnMoeCA9ICIiLCAKICAgICAgIHkgPSAiIikgKwogIG15X2dndGhlbWVfcChmYWNldF90eF9zID0gMjAsCiAgICAgICAgICAgICAgIGxlZ19wb3MgPSAiYm90dG9tIiwKICAgICAgICAgICAgICAgYXh4X3R4X2FuZyA9IDQ1LAogICAgICAgICAgICAgICBheF90eF9zID0gMTIsCiAgICAgICAgICAgICAgIGF4X3RsX3MgPSAxOCwKICAgICAgICAgICAgICAgaGp1c3QgPSAxKSArCiAgdGhlbWUobGVnZW5kLmtleS53aWR0aCA9IHVuaXQoNCwibGluZSIpLAogICAgICAgIGxlZ2VuZC50aXRsZS5hbGlnbj0wLjUsCiAgICAgICAgc3RyaXAudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgKSAKCmdnc2F2ZShmaWxlbmFtZSA9ICJwcm9wb3J0aW9uX2NobmdfYWdnLnBuZyIsCiAgICAgICAgIHBsb3QgPSBwcm9wX2NobmdfbWFwLAogICAgICAgICBwYXRoID0gbXlfcGF0aCgiUiIsIkZpZ3VyZXMiKSwKICAgICAgICAgd2lkdGggPSAxMCwKICAgICAgICAgaGVpZ2h0ID0gMTAKICApCgoKIyMjIyBPcHRpb24gd2l0aCBkaWZmZXJlbmNlcwoKIyBTZWFzb24gZGlmZmVyZW5jY2UKCnNwYXRfZGlmZiA8LSBsYW5kX3NmICU+JSAKICBsZWZ0X2pvaW4oZGlmZmVyZW5jZXMsCiAgICAgICAgICAgIGJ5ID0gInN0YXRlIikgJT4lIAogIGZpbHRlcighY2F0ZWdvcnkgJWluJSBjKCJmcCIsInN3IikpICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV9zZihhZXMoZmlsbCA9IGRpZmYpKSArCiAgdmlyaWRpczo6c2NhbGVfZmlsbF92aXJpZGlzKCJEaWZmZXJlbmNlcyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuOCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9uID0gIkMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDAsNTApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMCw1MCwxMCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSArCiAgZmFjZXRfd3JhcCh+IGxhYmVsLAogICAgICAgICAgICAgbmNvbCA9IDIpICsKICBsYWJzKHggPSAiIiwgCiAgICAgICB5ID0gIiIpICsKICBteV9nZ3RoZW1lX3AoZmFjZXRfdHhfcyA9IDIwLAogICAgICAgICAgICAgICBsZWdfcG9zID0gImJvdHRvbSIsCiAgICAgICAgICAgICAgIGF4eF90eF9hbmcgPSA0NSwKICAgICAgICAgICAgICAgYXhfdHhfcyA9IDEyLAogICAgICAgICAgICAgICBheF90bF9zID0gMTgsCiAgICAgICAgICAgICAgIGhqdXN0ID0gMSkgKwogIHRoZW1lKGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDQsImxpbmUiKSwKICAgICAgICBsZWdlbmQudGl0bGUuYWxpZ249MC41LAogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKQoKZ2dzYXZlKGZpbGVuYW1lID0gInNwYXRfZGlmZi5wbmciLAogICAgICAgICBwbG90ID0gc3BhdF9kaWZmLAogICAgICAgICBwYXRoID0gbXlfcGF0aCgiUiIsIkZpZ3VyZXMiKSwKICAgICAgICAgd2lkdGggPSA4LAogICAgICAgICBoZWlnaHQgPSA2CiAgKQoKIyBzZWFzb25hbApzZWFzX2RpZmYgPC0gbGFuZF9zZiAlPiUgCiAgbGVmdF9qb2luKGRpZmZlcmVuY2VzLAogICAgICAgICAgICBieSA9ICJzdGF0ZSIpICU+JSAKICBmaWx0ZXIoY2F0ZWdvcnkgJWluJSBjKCJmcCIsInN3IikpICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV9zZihhZXMoZmlsbCA9IGRpZmYpKSArCiAgdmlyaWRpczo6c2NhbGVfZmlsbF92aXJpZGlzKCJEaWZmZXJlbmNlcyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuOCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9uID0gIkMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDAsNTApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMCw1MCwxMCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSArCiAgZmFjZXRfd3JhcCh+IGxhYmVsLAogICAgICAgICAgICAgbmNvbCA9IDEsCiAgICAgICAgICAgICBzdHJpcC5wb3NpdGlvbj0icmlnaHQiKSArCiAgbGFicyh4ID0gIiIsIAogICAgICAgeSA9ICIiKSArCiAgbXlfZ2d0aGVtZV9wKGZhY2V0X3R4X3MgPSAyMCwKICAgICAgICAgICAgICAgbGVnX3BvcyA9ICIiLAogICAgICAgICAgICAgICBheHhfdHhfYW5nID0gNDUsCiAgICAgICAgICAgICAgIGF4X3R4X3MgPSAxMiwKICAgICAgICAgICAgICAgYXhfdGxfcyA9IDE4LAogICAgICAgICAgICAgICBoanVzdCA9IDEpICsKICB0aGVtZShzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICMgc3RyaXAudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMubGluZS55ID0gZWxlbWVudF9ibGFuaygpCiAgICAgICAgKQoKZ2dzYXZlKGZpbGVuYW1lID0gInNlYXNfZGlmZi5wbmciLAogICAgICAgICBwbG90ID0gc2Vhc19kaWZmLAogICAgICAgICBwYXRoID0gbXlfcGF0aCgiUiIsIkZpZ3VyZXMiKSwKICAgICAgICAgd2lkdGggPSA4LAogICAgICAgICBoZWlnaHQgPSA2CiAgKQoKCmBgYAoKCgoKYGBge3J9CgoKIyMjIFNSQUggTEFORElORyBEQVRBCiMgcmVhZF9leGNlbF9hbGxzaGVldHMgPC0gZnVuY3Rpb24oZmlsZW5hbWUsIHRpYmJsZSA9IFRSVUUpIHsKIyAgICAgIyBJIHByZWZlciBzdHJhaWdodCBkYXRhLmZyYW1lcwojICAgICAjIGJ1dCBpZiB5b3UgbGlrZSB0aWR5dmVyc2UgdGliYmxlcyAodGhlIGRlZmF1bHQgd2l0aCByZWFkX2V4Y2VsKQojICAgICAjIHRoZW4ganVzdCBwYXNzIHRpYmJsZSA9IFRSVUUKIyAgICAgc2hlZXRzIDwtIHJlYWR4bDo6ZXhjZWxfc2hlZXRzKGZpbGVuYW1lKVsyOjhdCiMgICAgIHggPC0gbGFwcGx5KHNoZWV0cywgZnVuY3Rpb24oWCkgcmVhZHhsOjpyZWFkX2V4Y2VsKGZpbGVuYW1lLCBzaGVldCA9IFgpKQojICAgICBpZighdGliYmxlKSB4IDwtIGxhcHBseSh4LCBhcy5kYXRhLmZyYW1lKQojICAgICBuYW1lcyh4KSA8LSBzaGVldHMKIyAgICAgeAojIH0KIyBHZXQgZGF0YSBwYXRoCiMgcG9ydHNfcGF0aCA8LSBteV9wYXRoKCJEIiwiTk9BQSIsIG5hbWUgPSAiU1NtaXRoXzIwMTUtMjAyMSBMYW5kaW5nc19KVU4gMjAyMS54bHN4IikKCiMgTG9hZCBwb3J0cwojIHBvcnRzX2RhdGEgPC0gYmluZF9yb3dzKHJlYWRfZXhjZWxfYWxsc2hlZXRzKHBvcnRzX3BhdGgpKSAlPiUKIyAgIGNsZWFuX25hbWVzKCkgJT4lCiMgICBtdXRhdGVfaWYoaXMuY2hhcmFjdGVyLAojICAgICAgICAgICAgICAgfiBzdHJfdG9fbG93ZXIoLikpICU+JQojICAgICBmaWx0ZXIoc3BlY2llc19uYW1lICVpbiUgYygic3VtbWVyIGZsb3VuZGVyIiwiYmxhY2sgc2VhIGJhc3MiLCJzY3VwIikpCgpgYGAKCg==